結果

問題 No.5015 Escape from Labyrinth
コンテスト
ユーザー FplusFplusF
提出日時 2026-05-11 11:52:48
言語 C++23
(gcc 15.2.0 + boost 1.89.0)
コンパイル:
g++-15 -O2 -lm -std=c++23 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
AC  
実行時間 813 ms / 3,000 ms
コード長 15,972 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 3,862 ms
コンパイル使用メモリ 372,156 KB
実行使用メモリ 33,280 KB
スコア 222,240
最終ジャッジ日時 2026-05-11 11:54:09
合計ジャッジ時間 79,799 ms
ジャッジサーバーID
(参考情報)
judge2_0 / judge1_0
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 100
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#include <bits/stdc++.h>
using namespace std;
using pii=pair<int,int>;
using tii=tuple<int,int,int>;
using qii=tuple<int,int,int,int>;
using ll=long long;
using ull=unsigned long long;
using ld=long double;
constexpr int INF=1e9;
constexpr ll INF_ll=1e18;
#define rep(i,n) for (int i=0;i<(int)(n);i++)
#define replr(i,l,r) for (int i=(int)(l);i<(int)(r);i++)
#define all(v) v.begin(),v.end()
#define len(v) ((int)v.size())
template<class T> inline bool chmin(T &a,T b){
    if(a>b){
        a=b;
        return true;
    }
    return false;
}
template<class T> inline bool chmax(T &a,T b){
    if(a<b){
        a=b;
        return true;
    }
    return false;
}

template<class T> inline bool chmin_ref(T &a,const T &b){
    if(a>b){
        a=b;
        return true;
    }
    return false;
}
template<class T> inline bool chmax_ref(T &a,const T &b){
    if(a<b){
        a=b;
        return true;
    }
    return false;
}

namespace Timer{
    chrono::steady_clock::time_point program_start,start;
    void program_start_snap(){
        program_start=start=chrono::steady_clock::now();
    }
    void snap(){
        start=chrono::steady_clock::now();
    }
    int get_ms(){
        auto now=chrono::steady_clock::now();
        int ms=chrono::duration_cast<chrono::milliseconds>(now-start).count();
        return ms;
    }
    int get_ms_all_program(){
        auto now=chrono::steady_clock::now();
        int ms=chrono::duration_cast<chrono::milliseconds>(now-program_start).count();
        return ms;
    }
}
//参考:https://ei1333.github.io/library/other/xor-shift.hpp.html

namespace Random{
    uint64_t x=88172645463325252;
    constexpr uint32_t mask=numeric_limits<uint32_t>::max();
    constexpr double k=1.0/(double)(numeric_limits<uint64_t>::max());
    inline uint64_t xorshift64(){
        x^=x<<7;
        x^=x>>9;
        return x;
    }
    inline uint32_t rand_int(uint32_t r){  //[0,r)
        assert(r!=0);
        return (xorshift64()&mask)*r>>32;
    }
    inline int rand_int(int l,int r){  //[l,r)
        assert(l<=r);
        return l+rand_int(r-l);
    }
    inline double rand_double(){  // [0.0,1.0]
        return xorshift64()*k;
    }
}
using Random::rand_int,Random::rand_double;

template<class T> T get_random_element(const vector<T> &v){
    assert(!v.empty());
    return v[rand_int(len(v))];
}

template<class T> void add(vector<T> &a,vector<T> b){
    for(auto i:b) a.push_back(i);
}

template<class SA_State,int limit_ms,double start_temp,double end_temp=0.0> SA_State SA(const SA_State &first_state){

    SA_State state=first_state,best_state=state;
    

    
    int loop_cnt=0,accept_cnt=0,update_cnt=0;
    
    int ms=0;
    
    double temp=start_temp;
    
    Timer::snap();
    
    
    constexpr int b=16,sz=1<<b;
    
    array<double,sz> log_rd;
    
    rep(i,sz) log_rd[i]=log(rand_double());
    
    
    while(true){

        if((loop_cnt&1023)==1023){
            
            ms=Timer::get_ms();
            
            if(limit_ms<=ms) break;
            
            temp=start_temp-(start_temp-end_temp)/limit_ms*ms;
        }
        
        loop_cnt++;
        
        double accept_diff=log_rd[loop_cnt&(sz-1)]*temp;

        bool accepted=state.modify(accept_diff);
        
        
        if(accepted){
            
            accept_cnt++;
        
            if(state.score<best_state.score){
                best_state=state;
                //cerr << "score:" << best_state.score << " ms:" << ms << " loop_cnt:" << loop_cnt << " accept_cnt:" << accept_cnt << " update_cnt:" << update_cnt << '\n';
                update_cnt++;
            }
        }
    }

    
    cerr << "[result] " << "score:" << best_state.score << " ms:" << ms << " loop_cnt:" << loop_cnt << " accept_cnt:" << accept_cnt << " update_cnt:" << update_cnt << '\n';
    
    return best_state;
};


constexpr int N=60,H=1500,L=60;

int D,M;

string S;

constexpr string UDLR="UDLR";

vector<int> P,K;

array<array<int,5>,N*N> G;

int Start,Key,Goal;

int one(int i,int j){
    return i*N+j;
}
pii two(int x){
    return {x/N,x%N};
}

namespace Solver{
    
    array<array<int,L>,N*N> grid_damage;
    
    
    array<array<double,N*N>,N*N> two_dist;
    array<array<int,N*N>,N*N> two_dist_pre;
    
    
    array<double,N*N> grid_expected_damage;
    
    struct SA_State{
        
        vector<vector<double>> edge_dist;
        
        int sz=0;
        double score=INF;
        
        vector<int> ord;
        
        vector<int> idx_pos;
        
        SA_State(){
            
            
            idx_pos.push_back(Start);
            rep(i,N*N){
                if((S[i]=='J'||i==Key)&&two_dist[Start][i]<=H) idx_pos.push_back(i);
            }
            idx_pos.push_back(Goal);
            
            sz=len(idx_pos);
            
            ord.resize(sz);
            rep(i,sz) ord[i]=i;
            
            edge_dist.resize(sz,vector<double>(sz,0));
            
            rep(i,sz){
                rep(j,sz){
                    if(i==j) continue;
                    
                    if(idx_pos[i]==Goal){
                        edge_dist[i][j]=min<double>(H,two_dist[idx_pos[j]][idx_pos[i]]-grid_expected_damage[idx_pos[i]]);
                    }else{
                        edge_dist[i][j]=min<double>(H,two_dist[idx_pos[i]][idx_pos[j]]-grid_expected_damage[idx_pos[j]]);
                    }
                }
            }
            
            score=calc_score();
        }
        
        double calc_score() const{
            double ret=0;
            rep(i,sz-1){
                ret+=edge_dist[ord[i]][ord[i+1]];
            }
            return ret;
        }
        
        bool modify(double accept_diff){
            
            int l=rand_int(1,sz-1),r=rand_int(1,sz-1);
            if(l==r) return false;
            if(r<l) swap(l,r);
            
            
            double new_score=score;
            
            new_score-=edge_dist[ord[l-1]][ord[l]];
            new_score+=edge_dist[ord[l-1]][ord[r]];
            new_score-=edge_dist[ord[r]][ord[r+1]];
            new_score+=edge_dist[ord[l]][ord[r+1]];
            
            
            if(accept_diff<=score-new_score){
                reverse(ord.begin()+l,ord.begin()+r+1);
                score=new_score;
                return true;
            }else{
                return false;
            }
        }
        
        vector<int> get_pos(){
            vector<int> ret(sz);
            rep(i,sz){
                ret[i]=idx_pos[ord[i]];
            }
            return ret;
        }
    };
    
    
    
    
    pair<vector<int>,vector<int>> dijkstra_cost(int s,int start_turn,bool goal_ng,const vector<int> &gs){
        
        static array<array<int,L>,N*N> cost;
        static array<array<int,L>,N*N> turn;
        static array<array<int,L>,N*N> last_vis;
    
        static int vis_cnt=0;
        
        if(vis_cnt==0){
            rep(i,N*N){
                cost[i].fill(INF);
                last_vis[i].fill(-1);
            }
        }
        
        vis_cnt++;
        
        int ts=start_turn%L;
        
        cost[s][ts]=0;
        last_vis[s][ts]=vis_cnt;
        turn[s][ts]=0;
        priority_queue<tii,vector<tii>,greater<tii>> pq;
        pq.push({0,s,ts});
        
        unordered_set<int> st(all(gs));
        
        unordered_map<int,int> mp;
        
        while(!pq.empty()){
            
            auto [d,x,tx]=pq.top();
            pq.pop();
            
            if(cost[x][tx]!=d) continue;
            
            if(st.contains(x)){
                st.erase(x);
                mp[x]=tx;
                if(st.empty()) break;
            }
            
            if(goal_ng&&x==Goal) continue;
            
            int ty=(tx+1)%L;
            
            for(auto y:G[x]){
                if(y==-1) continue;
                if(last_vis[y][ty]!=vis_cnt||cost[x][tx]+grid_damage[y][ty]<cost[y][ty]){
                    cost[y][ty]=cost[x][tx]+grid_damage[y][ty];
                    pq.push({cost[y][ty],y,ty});
                    turn[y][ty]=turn[x][tx]+1;
                    last_vis[y][ty]=vis_cnt;
                }
            }
        }
        
        vector<int> ret_cost,ret_turn;
        
        for(auto g:gs){
            /*if(last_vis[g][mp[g]]!=vis_cnt){
                auto [si,sj]=two(s);
                auto [gi,gj]=two(g);
                cerr << si << " " << sj << " " << gi << " " << gj << endl;
            }*/
            assert(last_vis[g][mp[g]]==vis_cnt);
            ret_cost.push_back(cost[g][mp[g]]);
            ret_turn.push_back(turn[g][mp[g]]);
        }
        return {ret_cost,ret_turn};
    }
    
    vector<int> dijkstra_route(int s,int start_turn,bool goal_ng,int g){
        
        static array<array<int,L>,N*N> cost;
        static array<array<int,L>,N*N> turn;
        static array<array<pii,L>,N*N> pre;
        static array<array<int,L>,N*N> last_vis;
    
        static int vis_cnt=0;
        
        if(vis_cnt==0){
            rep(i,N*N){
                cost[i].fill(INF);
                pre[i].fill({-1,-1});
                last_vis[i].fill(-1);
            }
        }
        
        vis_cnt++;
        
        int ts=start_turn%L;
        
        cost[s][ts]=0;
        last_vis[s][ts]=vis_cnt;
        turn[s][ts]=0;
        priority_queue<tii,vector<tii>,greater<tii>> pq;
        pq.push({0,s,ts});
        
        int tg=-1;
        
        
        while(!pq.empty()){
            
            auto [d,x,tx]=pq.top();
            pq.pop();
            if(cost[x][tx]!=d) continue;
            
            if(g!=-1&&x==g){
                tg=tx;
                break;
            }
            
            if(goal_ng&&x==Goal) continue;
            
            int ty=(tx+1)%L;
            
            for(auto y:G[x]){
                if(y==-1) continue;
                if(last_vis[y][ty]!=vis_cnt||cost[x][tx]+grid_damage[y][ty]<cost[y][ty]){
                    cost[y][ty]=cost[x][tx]+grid_damage[y][ty];
                    pq.push({cost[y][ty],y,ty});
                    pre[y][ty]={x,tx};
                    turn[y][ty]=turn[x][tx]+1;
                    last_vis[y][ty]=vis_cnt;
                }
            }
        }
        
        assert(tg!=-1);
        
        vector<int> ret;
        
        int x=g,tx=tg;
            
        while(!(x==s&&tx==ts)){
            
            ret.push_back(x);
            auto [y,ty]=pre[x][tx];
            assert(y!=-1);
            assert(ty!=-1);
            x=y;
            tx=ty;
        }
        
        reverse(all(ret));
        
        return ret;
    }
    
    void output_ans(vector<int> ans){
        
        int x=Start;
        
        for(auto p:ans){
            int t=-1;
            rep(k,5){
                if(G[x][k]==p) t=k;
            }
            assert(t!=-1);
            if(t==4) cout << "S\n";
            else cout << "M " << UDLR[t] << '\n';
            
            x=p;
        }
    }
    
    void solve(){
        
        rep(i,N*N) grid_damage[i].fill(1);
        
        rep(m,M){
            rep(k,4){
                int p=P[m];
                while(p!=-1){
                    p=G[p][k];
                    if(p!=-1){
                        for(int t=0;t<L;t+=K[m]){
                            grid_damage[p][t]+=D;
                        }
                    }
                }
            }
        }
        
        
        grid_expected_damage.fill(0);
        
        rep(i,N*N){
            double sum=0;
            rep(l,L){
                sum+=(grid_damage[i][l]-1);
            }
            grid_expected_damage[i]=1+sum/L;
        }
        
        rep(s,N*N){
            
            if(!(S[s]=='J'||s==Start||s==Key||s==Goal)) continue;
            
            two_dist[s].fill(INF);
            two_dist[s][s]=0;
            two_dist_pre[s].fill(-1);
            
            priority_queue<pair<double,int>,vector<pair<double,int>>,greater<pair<double,int>>> pq;
            pq.push({0,s});
            
            while(!pq.empty()){
                auto [d,x]=pq.top();
                pq.pop();
                
                if(1e-4<abs(d-two_dist[s][x])) continue;
                
                if(x==Goal) continue;  //Goalを閉じて途中で終了しないようにごまかしている
                
                for(auto y:G[x]){
                    if(y==-1) continue;
                    if(chmin(two_dist[s][y],two_dist[s][x]+grid_expected_damage[y])){
                        two_dist_pre[s][y]=x;
                        pq.push({two_dist[s][y],y});
                    }
                }
            }
        }
        
        SA_State sa_state;
        
        sa_state=SA<SA_State,500,10.0>(sa_state);
        
        vector<int> pos=sa_state.get_pos();
        
        int sz=len(pos);
        
        constexpr int P=300;
        
        vector<vector<double>> dp(sz,vector<double>(P,INF));  //[pos_index][cnt]={damage,turn}
        vector<vector<pii>> pre(sz,vector<pii>(P,{-1,-1}));
        
        dp[0][0]=0;
        
        bool have_key=false;
        
        int key_idx=-1;
        
        rep(i,sz){
            if(pos[i]==Key) key_idx=i;
        }
        
        assert(key_idx!=-1);
        
        rep(i,sz-1){
            
            rep(c,P-1){
                replr(j,i+1,min(sz,i<key_idx?key_idx+1:INF)){
                    if(chmin(dp[j][c+1],dp[i][c]+two_dist[pos[i]][pos[j]])){
                        pre[j][c+1]={i,c};
                    }
                }
            }
        }
        
        
        for(int c=P-1;0<=c;c--){
            
            if(H*1.5<=dp[sz-1][c]) continue;
            
            assert(Timer::get_ms_all_program()<=2900);
            
            int xi=sz-1,xc=c;
            vector<int> dp_route;
            
            while(!(xi==0&&xc==0)){
                dp_route.push_back(xi);
                auto [pi,pc]=pre[xi][xc];
                xi=pi;
                xc=pc;
            }
            
            reverse(all(dp_route));
            
            
            vector<int> ans;
            int pos_idx=0;
            have_key=false;
            
            int turn=0;
            int cost_sum=0;
            
            for(auto e_idx:dp_route){
                if(pos[e_idx]==Key) have_key=true;
                vector<int> now=dijkstra_route(pos[pos_idx],len(ans),have_key,pos[e_idx]);
                pos_idx=e_idx;
                add(ans,now);
                
                for(auto e:now){
                    turn++;
                    cost_sum+=grid_damage[e][turn%L];
                }
                if(H<cost_sum) break;
            }
            
            if(H<cost_sum) continue;
            
            
            output_ans(ans);
            
            return;
        }
        
        assert(0);
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    Timer::program_start_snap();
    
    int n,h;
    
    cin >> n >> D >> h;
    
    rep(i,N){
        string s;
        cin >> s;
        S+=s;
    }
    
    cin >> M;
    
    P.resize(M);
    K.resize(M);
    
    rep(i,M){
        int y,x;
        cin >> y >> x >> K[i];
        P[i]=one(y,x);
    }
    
    vector<int> pi={-1,1,0,0,0},pj={0,0,-1,1,0};
    
    rep(i,N){
        rep(j,N){
            G[one(i,j)].fill(-1);
            
            //if(S[one(i,j)]=='#'||S[one(i,j)]=='E') continue;
            
            rep(k,5){
                int ti=i+pi[k],tj=j+pj[k];
                if(ti<0||N<=ti||tj<0||N<=tj) continue;
                if(S[one(ti,tj)]=='#'||S[one(ti,tj)]=='E') continue;
                G[one(i,j)][k]=one(ti,tj);
            }
        }
    }
    
    rep(i,N*N){
        if(S[i]=='S') Start=i;
        if(S[i]=='K') Key=i;
        if(S[i]=='G') Goal=i;
    }
    Solver::solve();
    exit(0);
}
0