#include using namespace std; using pii=pair; using tii=tuple; using qii=tuple; 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 inline bool chmin(T &a,T b){ if(a>b){ a=b; return true; } return false; } template inline bool chmax(T &a,T b){ if(a inline bool chmin_ref(T &a,const T &b){ if(a>b){ a=b; return true; } return false; } template inline bool chmax_ref(T &a,const T &b){ if(a(now-start).count(); return ms; } int get_ms_all_program(){ auto now=chrono::steady_clock::now(); int ms=chrono::duration_cast(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::max(); constexpr double k=1.0/(double)(numeric_limits::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 T get_random_element(const vector &v){ assert(!v.empty()); return v[rand_int(len(v))]; } template void add(vector &a,vector b){ for(auto i:b) a.push_back(i); } template 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< log_rd; rep(i,sz) log_rd[i]=log(rand_double()); while(true){ //if(loop_cnt==5e7) break; if((loop_cnt&1023)==1023){ ms=Timer::get_ms(); if(limit_ms<=ms) break; temp=start_temp-(start_temp-end_temp)/limit_ms*ms; //temp=start_temp-(start_temp-end_temp)/5e7*loop_cnt; } 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 P,K; array,N*N> G; //TODO:4にする? array Detector_mod; int Start,Key,Goal; int one(int i,int j){ return i*N+j; } pii two(int x){ return {x/N,x%N}; } namespace DP{ vector tour; array last_vis; struct Action{ int action=-1; int dir=-1; Action(int action_,int dir_):action(action_),dir(dir_){} Action(){} }; struct Candidate{ pii parent={-1,-1}; Action action; int damage=INF; int block_cnt=0; Candidate(pii parent_,Action action_,int damage_,int block_cnt_):parent(parent_),action(action_),damage(damage_),block_cnt(block_cnt_){} Candidate(){} auto operator<=>(const Candidate &other) const{ return pii{damage,-block_cnt}<=>pii{other.damage,-other.block_cnt}; } }; struct State{ bitset is_block; int damage=INF; int block_cnt=0; int turn=0; int tour_idx=0; void init(){ damage=0; } int calc_damage(int now_turn,int now_pos) const{ int ret=1; rep(k,4){ int p=now_pos; while(true){ p=G[p][k]; if(p==-1) break; if(is_block[p]) break; if(Detector_mod[p]!=-1){ if(now_turn%Detector_mod[p]==0) ret+=D; break; } } } return ret; } void push_candidates(vector> &best_candidates){ assert(tour_idx+1 &tour_){ tour=tour_; last_vis.fill(-1); rep(i,len(tour)){ last_vis[tour[i]]=i; } int sz=len(tour); vector> dp(sz); vector> best_candidates(sz,vector(2*L)); dp[0].resize(2*L); dp[0][0].init(); rep(i,sz-1){ dp[i+1].resize(2*L); if(0<=i-2){ dp[i-2].clear(); dp[i-2].shrink_to_fit(); } bool ok=false; rep(j,2*L){ if(!(i==0&&j==0)){ if(H actions; while(!(ni==0&&nj==0)){ actions.push_back(best_candidates[ni][nj].action); auto [pi,pj]=best_candidates[ni][nj].parent; ni=pi; nj=pj; } reverse(all(actions)); State state; state.init(); for(auto action:actions){ if(action.action==0){ assert(state.tour_idx+1,N*N> grid_damage; array,N*N> two_dist; array,N*N> two_dist_pre; array grid_expected_damage; struct SA_State{ vector> edge_dist; int sz=0; double score=INF; vector ord; vector 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(sz,0)); rep(i,sz){ rep(j,sz){ if(i==j) continue; if(idx_pos[i]==Goal){ edge_dist[i][j]=min(H,two_dist[idx_pos[j]][idx_pos[i]]-grid_expected_damage[idx_pos[i]]); }else{ edge_dist[i][j]=min(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 get_pos(){ vector ret(sz); rep(i,sz){ ret[i]=idx_pos[ord[i]]; } return ret; } }; void solve(){ rep(i,N*N) grid_damage[i].fill(1); Detector_mod.fill(-1); rep(m,M){ Detector_mod[P[m]]=K[m]; } rep(m,M){ rep(k,4){ int p=P[m]; while(p!=-1){ p=G[p][k]; if(S[p]=='E') break; if(p!=-1){ for(int t=0;t,vector>,greater>> pq; pq.push({0,s}); while(!pq.empty()){ auto [d,x]=pq.top(); pq.pop(); if(1e-4(sa_state); vector pos=sa_state.get_pos(); int sz=len(pos); int P=min(320,sz); vector> dp(sz,vector(P,INF)); //[pos_index][cnt]={damage,turn} vector> pre(sz,vector(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 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 tour; tour.push_back(Start); int pos_idx=0; for(auto e_idx:dp_route){ vector 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); } cerr << c << endl; DP::calc_dp(tour); } 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 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)]=='#') 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); }