結果

問題 No.5015 Escape from Labyrinth
コンテスト
ユーザー FplusFplusF
提出日時 2026-05-12 08:50:25
言語 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  
実行時間 683 ms / 3,000 ms
コード長 13,121 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 5,065 ms
コンパイル使用メモリ 365,580 KB
実行使用メモリ 160,500 KB
スコア 228,090
最終ジャッジ日時 2026-05-12 08:51:43
合計ジャッジ時間 75,216 ms
ジャッジサーバーID
(参考情報)
tmp-judge_1 / judge3_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<int,vector<int>> tour_to_ans(const vector<int> &tour){
        int sz=len(tour);
        vector<vector<int>> dp(sz,vector<int>(L,INF));
        vector<vector<pii>> pre(sz,vector<pii>(L,{-1,-1}));
        dp[0][0]=0;
        
        rep(i,sz-1){
            rep(_,2){
                rep(a,L){
                    int b=(a+1)%L;
                    if(chmin(dp[i+1][b],dp[i][a]+grid_damage[tour[i+1]][b])){
                        pre[i+1][b]={i,a};
                    }
                    if(chmin(dp[i][b],dp[i][a]+grid_damage[tour[i]][b])){
                        pre[i][b]={i,a};
                    }
                }
            }
        }
        int min_cost=INF;
        
        int xi=-1,xj=-1;
        
        rep(i,L){
            if(chmin(min_cost,dp[sz-1][i])){
                xi=sz-1;
                xj=i;
            }
        }
        
        assert(xi!=-1);
        
        vector<int> ret;
        
        while(!(xi==0&&xj==0)){
            ret.push_back(tour[xi]);
            auto [pi,pj]=pre[xi][xj];
            xi=pi;
            xj=pj;
        }
        
        reverse(all(ret));
        return {min_cost,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;
        
        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> tour;
            
            tour.push_back(Start);
            
            int pos_idx=0;
            
            for(auto e_idx:dp_route){
                vector<int> now;
                
                int x=pos[e_idx];
                
                while(x!=pos[pos_idx]){
                    now.push_back(x);
                    x=two_dist_pre[pos[pos_idx]][x];
                }
                
                reverse(all(now));
                
                pos_idx=e_idx;
                add(tour,now);
            }
            
            
            auto [cost_sum,ans]=tour_to_ans(tour);
            
            //cerr << cost_sum << endl;
            
            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