結果
問題 | No.5019 Hakai Project |
ユーザー | ぴぃいいいい |
提出日時 | 2023-11-19 02:09:45 |
言語 | C++23 (gcc 12.3.0 + boost 1.83.0) |
結果 |
TLE
|
実行時間 | - |
コード長 | 20,629 bytes |
コンパイル時間 | 6,405 ms |
コンパイル使用メモリ | 335,552 KB |
実行使用メモリ | 6,676 KB |
スコア | 2,452,381,639 |
最終ジャッジ日時 | 2023-11-19 02:11:55 |
合計ジャッジ時間 | 26,550 ms |
ジャッジサーバーID (参考情報) |
judge15 / judge14 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2,159 ms
6,676 KB |
testcase_01 | TLE | - |
testcase_02 | AC | 2,532 ms
6,676 KB |
testcase_03 | AC | 2,289 ms
6,676 KB |
testcase_04 | AC | 2,181 ms
6,676 KB |
testcase_05 | AC | 2,103 ms
6,676 KB |
testcase_06 | AC | 2,162 ms
6,676 KB |
testcase_07 | AC | 2,787 ms
6,676 KB |
testcase_08 | AC | 2,294 ms
6,676 KB |
testcase_09 | AC | 2,998 ms
6,676 KB |
testcase_10 | AC | 1,836 ms
6,676 KB |
testcase_11 | AC | 2,466 ms
6,676 KB |
testcase_12 | AC | 2,509 ms
6,676 KB |
testcase_13 | AC | 2,446 ms
6,676 KB |
testcase_14 | AC | 2,003 ms
6,676 KB |
testcase_15 | AC | 2,234 ms
6,676 KB |
testcase_16 | AC | 2,158 ms
6,676 KB |
testcase_17 | AC | 1,510 ms
6,676 KB |
testcase_18 | AC | 2,319 ms
6,676 KB |
testcase_19 | AC | 2,176 ms
6,676 KB |
testcase_20 | AC | 2,596 ms
6,676 KB |
testcase_21 | AC | 2,578 ms
6,676 KB |
testcase_22 | AC | 2,070 ms
6,676 KB |
testcase_23 | AC | 2,437 ms
6,676 KB |
testcase_24 | AC | 2,706 ms
6,676 KB |
testcase_25 | AC | 2,407 ms
6,676 KB |
testcase_26 | AC | 2,364 ms
6,676 KB |
testcase_27 | AC | 1,929 ms
6,676 KB |
testcase_28 | AC | 2,009 ms
6,676 KB |
testcase_29 | AC | 1,826 ms
6,676 KB |
testcase_30 | AC | 2,195 ms
6,676 KB |
testcase_31 | AC | 2,295 ms
6,676 KB |
testcase_32 | AC | 2,564 ms
6,676 KB |
testcase_33 | AC | 2,096 ms
6,676 KB |
testcase_34 | AC | 2,714 ms
6,676 KB |
testcase_35 | AC | 2,072 ms
6,676 KB |
testcase_36 | AC | 1,835 ms
6,676 KB |
testcase_37 | AC | 2,251 ms
6,676 KB |
testcase_38 | AC | 2,141 ms
6,676 KB |
testcase_39 | AC | 2,281 ms
6,676 KB |
testcase_40 | AC | 2,539 ms
6,676 KB |
testcase_41 | AC | 2,294 ms
6,676 KB |
testcase_42 | AC | 2,062 ms
6,676 KB |
testcase_43 | AC | 1,930 ms
6,676 KB |
testcase_44 | AC | 2,288 ms
6,676 KB |
testcase_45 | AC | 1,636 ms
6,676 KB |
testcase_46 | AC | 2,249 ms
6,676 KB |
testcase_47 | AC | 1,976 ms
6,676 KB |
testcase_48 | AC | 2,768 ms
6,676 KB |
testcase_49 | TLE | - |
コンパイルメッセージ
main.cpp: In member function 'void State::one_step2()': main.cpp:511:48: warning: 'best_t' may be used uninitialized [-Wmaybe-uninitialized] 511 | int best_explode_x = i-a[best_k][best_t]; | ^ main.cpp:470:20: note: 'best_t' was declared here 470 | int best_k,best_t; | ^~~~~~ In member function 'void State::use(int)', inlined from 'void State::one_step2()' at main.cpp:517:12: main.cpp:325:26: warning: 'best_k' may be used uninitialized [-Wmaybe-uninitialized] 325 | for(int j=0;j<l[i];j++){ | ~~~^ main.cpp: In member function 'void State::one_step2()': main.cpp:470:13: note: 'best_k' was declared here 470 | int best_k,best_t; | ^~~~~~ main.cpp:467:18: warning: 'j' may be used uninitialized [-Wmaybe-uninitialized] 467 | if(A[i][j]=='.') return; | ^ main.cpp:461:15: note: 'j' was declared here 461 | int i,j; | ^ main.cpp:467:15: warning: 'i' may be used uninitialized [-Wmaybe-uninitialized] 467 | if(A[i][j]=='.') return; | ^ main.cpp:461:13: note: 'i' was declared here 461 | int i,j; | ^ In member function 'void Bombplan::greedy_all()', inlined from 'Bombplan::Bombplan(std::vector<std::vector<char> >)' at main.cpp:54:19, inlined from 'void Solve::solve()' at main.cpp:586:28: main.cpp:102:35: warning: 'best_k' may be used uninitialized [-Wmaybe-uninitialized] 102 | for(int x=0;x<l[best_k];x++){ | ~~~~~~~~^ main.cpp: In member function 'void Solve::solve()': main.cpp:80:31: note: 'best_k' was declared here 80 | int best_i,best_j,best_k; | ^~~~~~ In file included from /home/linuxbrew/.linuxbrew/Cellar/gcc@12/12.3.0/include/c++/12/functional:54, from /home/linuxbrew/.li
ソースコード
#pragma GCC optimize("O3") #include<bits/stdc++.h> using namespace std; #define Yes(n) cout << ((n) ? "Yes" : "No" ) << endl #define print(var) std::cout<<#var<<"="<<(var)<<std::endl #define all(a) (a).begin(), (a).end() #define vi vector<int> #define vvi vector<vi> #define vvvi vector<vvi> #define ll long long #define vll vector<ll> #define vvll vector<vll> #define vvvll vector<vvll> #define vmi vector<mint> #define vvmi vector<vmi> #define vvvmi vector<vvmi> #define vs vector<string> #define pii pair<int,int> #define vpii vector<pair<int,int>> #define bit(x,i)(((x)>>(i))&1) #define inf (1<<30) #define INF (1ll<<60) template<typename T> inline bool chmax(T &a, T b) { return ((a < b) ? (a = b, true) : (false)); } template<typename T> inline bool chmin(T &a, T b) { return ((a > b) ? (a = b, true) : (false)); } inline double get_time() { using namespace std::chrono; return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count(); } unsigned long xor128(void){ static unsigned long x=123456789,y=362436069,z=521288629,w=88675123; unsigned long t; t=(x^(x<<11));x=y;y=z;z=w; return( w=(w^(w>>19))^(t^(t>>8)) ); } long long randInt(long long a,long long b){return a+xor128()%(b-a+1);} double randDouble(double a,double b){return a+(b-a)*xor128()/(double)ULONG_MAX;} double start_time; int n,m; int c[20],l[20]; vector<int> a[20],b[20]; bool is_valid(int x,int y){ return 0<=x && x<n && 0<=y && y<n; } struct Bombplan{ vector<vector<char>> A; vector<vector<tuple<int,int,int>>> plan; Bombplan(){} Bombplan(vector<vector<char>> AA):A(AA){ plan.resize(n,vector<tuple<int,int,int>>(n)); greedy_all(); } //a[i][j]の爆破方法をランダムに決める void random_generate(int i,int j){ if(A[i][j]=='.') return; int k,x; do{ k = randInt(0,m-1); x = randInt(0,l[k]); }while(!is_valid(i-a[k][x],j-b[k][x])); plan[i][j] = make_tuple(k,i-a[k][x],j-b[k][x]); } //すべての位置の爆破方法をランダムに決める void random_all(){ for(int i=0;i<n;i++)for(int j=0;j<n;j++) random_generate(i,j); } //すべての位置の爆破方法をgreedyに決める void greedy_all(){ vector<vector<char>> AA = A; int building = 0; for(int i=0;i<n;i++)for(int j=0;j<n;j++){ if(AA[i][j]=='.') continue; building++; } while(building>0){ int best_i,best_j,best_k; double best = (double)INF; for(int iter=0;iter<10000;iter++){ int i = randInt(0,n-1); int j = randInt(0,n-1); int k = randInt(0,m-1); int broken_cnt = 0; for(int x=0;x<l[k];x++){ int broken_x = i+a[k][x]; int broken_y = j+b[k][x]; if(is_valid(broken_x,broken_y) && AA[broken_x][broken_y]!='.'){ broken_cnt++; } } if(broken_cnt==0) continue; double tmp = (double)c[k]/(double)broken_cnt; if(chmin(best,tmp)){ best_i = i; best_j = j; best_k = k; } } for(int x=0;x<l[best_k];x++){ int broken_x = best_i+a[best_k][x]; int broken_y = best_j+b[best_k][x]; if(!is_valid(broken_x,broken_y)) continue; if(AA[broken_x][broken_y]=='.') continue; AA[broken_x][broken_y] = '.'; building--; plan[broken_x][broken_y] = make_tuple(best_k,best_i,best_j); } } } //ランダムな一か所の爆破方法を変更する void random_trans_plan(){ int i,j; do{ i = randInt(0,n-1); j = randInt(0,n-1); }while(A[i][j]=='.'); random_generate(i,j); compress(i,j); } void compress(int i,int j){ if(A[i][j]=='.') return; auto [k,x,y] = plan[i][j]; for(int t=0;t<l[k];t++){ int broken_x = x+a[k][t]; int broken_y = y+b[k][t]; if(!is_valid(broken_x,broken_y)) continue; if(A[broken_x][broken_y]=='.') continue; plan[broken_x][broken_y] = plan[i][j]; } } void compress_all(){ vector<vector<bool>> dicided(n,vector<bool>(n)); vector<pii> que; for(int i=0;i<n;i++)for(int j=0;j<n;j++){ if(A[i][j]=='.') continue; que.push_back(make_pair(i,j)); } //queを真ん中からの距離で並び替え sort(all(que),[](pii a,pii b){ return abs(a.first-n/2)+abs(a.second-n/2) < abs(b.first-n/2)+abs(b.second-n/2); }); //queを順番に見ていく //queの中でまだ決まっていない建物を見つけて確定させる for(auto [i,j]:que){ if(dicided[i][j]) continue; auto [k,x,y] = plan[i][j]; for(int t=0;t<l[k];t++){ int broken_x = x+a[k][t]; int broken_y = y+b[k][t]; if(!is_valid(broken_x,broken_y)) continue; if(A[broken_x][broken_y]=='.') continue; if(dicided[broken_x][broken_y]) continue; dicided[broken_x][broken_y] = true; plan[broken_x][broken_y] = make_tuple(k,x,y); } } } set<tuple<int,int,int>> explode_list(){ set<tuple<int,int,int>> res; for(int i=0;i<n;i++)for(int j=0;j<n;j++){ if(A[i][j]=='.') continue; res.insert(plan[i][j]); } return res; } double eval(){ Bombplan bombplan = *this; double res = 0; bombplan.compress_all(); auto bombplan_explode_list = bombplan.explode_list(); for(auto [k,x,y]:bombplan_explode_list){ res += c[k]; } return res; } //出力 void output(){ auto res = explode_list(); for(auto [k,x,y]:res){ cerr<<x<<" "<<y<<" "<<k<<endl; } } }; struct State{ vector<vector<char>> A; int center_shop_x; int center_shop_y; vector<int> bomb; int bomb_sum=0; vector<pair<int,int>> hist; int building = 0; int shop = 0; ll cost=0; int buy_cost=0; int move_cost=0; int nowx=0,nowy=0; queue<pii> que; State(){} State(vector<vector<char>> AA):A(AA){ bomb.resize(m); vpii tmp; int min_center_dist = inf; for(int i=0;i<n;i++)for(int j=0;j<n;j++){ if(A[i][j]=='.') continue; tmp.emplace_back(make_pair(i,j)); building++; if(A[i][j]=='@'){ shop++; if(chmin(min_center_dist,abs(i-n/2)+abs(j-n/2))){ center_shop_x = i; center_shop_y = j; } } } sort(all(tmp),[](pii x, pii y){ int x_dist = abs(x.first-n/2)+abs(x.second-n/2); int y_dist = abs(y.first-n/2)+abs(y.second-n/2); if(x_dist==y_dist) return atan2(x.second-n/2,x.first-n/2) < atan2(y.second-n/2,y.first-n/2); return x_dist>y_dist; }); for(auto e:tmp){ que.push(e); } } pair<int,vector<char>> smart_route(int sx,int sy,int gx,int gy){ char x_ope = gx>sx ? 'D' : 'U'; int dx = gx>sx ? 1 : -1; char y_ope = gy>sy ? 'R' : 'L'; int dy = gy>sy ? 1 : -1; vvi dp(abs(gx-sx)+1,vi(abs(gy-sy)+1,inf)); dp[0][0] = 0; for(int i=0;i<=abs(gx-sx);i++)for(int j=0;j<=abs(gy-sy);j++){ if(i+1<=abs(gx-sx)){ chmin(dp[i+1][j],dp[i][j]+(A[sx+dx*(i+1)][sy+dy*j]!='.')+1); } if(j+1<=abs(gy-sy)){ chmin(dp[i][j+1],dp[i][j]+(A[sx+dx*i][sy+dy*(j+1)]!='.')+1); } } //dpから最短経路を復元 vector<char> res(abs(gx-sx) + abs(gy-sy)); int i=abs(gx-sx),j=abs(gy-sy); int index = res.size() - 1; while(i>0 || j>0){ if(i>0 && dp[i-1][j]+(A[sx+dx*i][sy+dy*j]!='.')+1==dp[i][j]){ res[index] = x_ope; i--; } else{ res[index] = y_ope; j--; } index--; } int cost = dp[abs(gx-sx)][abs(gy-sy)]; return make_pair(cost,res); } //d:方向 void move(char d){ if(d=='U'){ hist.emplace_back(make_pair(1,0)); nowx--; } if(d=='D'){ hist.emplace_back(make_pair(1,1)); nowx++; } if(d=='L'){ hist.emplace_back(make_pair(1,2)); nowy--; } if(d=='R'){ hist.emplace_back(make_pair(1,3)); nowy++; } if(A[nowx][nowy]=='.'){ cost += (bomb_sum+1)*(bomb_sum+1); move_cost += (bomb_sum+1)*(bomb_sum+1); } else{ cost += 2*(bomb_sum+1)*(bomb_sum+1); move_cost += 2*(bomb_sum+1)*(bomb_sum+1); } } //x,y:目的地の座標 void move(int x,int y){ pair<int, vector<char>> route_result = smart_route(nowx, nowy, x, y); for (char direction : route_result.second) { move(direction); } } //piiに対応する座標に移動する void move(pii p){ move(p.first,p.second); } //爆弾を買う //i:爆弾の種類 void buy(int i){ assert(i>=0 && i<m); hist.emplace_back(make_pair(2,i)); bomb[i]++; bomb_sum++; cost+=c[i]; buy_cost+=c[i]; } //爆弾を使う //i:爆弾の種類 void use(int i){ assert(i>=0 && i<m); hist.emplace_back(make_pair(3,i)); for(int j=0;j<l[i];j++){ int broken_x = nowx+a[i][j]; int broken_y = nowy+b[i][j]; if(!is_valid(broken_x,broken_y)) continue; if(A[broken_x][broken_y]=='.') continue; if(A[broken_x][broken_y]=='@'){ shop--; } building--; A[broken_x][broken_y]='.'; } bomb[i]--; bomb_sum--; } //爆弾を使ったときに壊れる建物の数,壊れる店の数,center_shopが壊れるかどうかを返す tuple<int,int,bool> use_simulate(int i,int x,int y){ assert(i>=0 && i<m); int broken_building = 0; int broken_shop = 0; bool broken_center_shop = false; for(int j=0;j<l[i];j++){ int broken_x = x+a[i][j]; int broken_y = y+b[i][j]; if(!is_valid(broken_x,broken_y)) continue; if(A[broken_x][broken_y]=='.') continue; if(A[broken_x][broken_y]=='@'){ broken_shop++; if(broken_x==center_shop_x && broken_y==center_shop_y){ broken_center_shop = true; } } broken_building++; } return make_tuple(broken_building,broken_shop,broken_center_shop); } //最も近い店の座標を返す pii nearest_shop(){ int min_dist=inf; pii res; for(int i=0;i<n;i++)for(int j=0;j<n;j++){ if(A[i][j]=='@'){ if(chmin(min_dist,abs(nowx-i)+abs(nowy-j))){ res = make_pair(i,j); } } } assert(min_dist!=inf); return res; } pii nearest_shop(int x, int y){ int min_dist=inf; pii res; for(int i=0;i<n;i++)for(int j=0;j<n;j++){ if(A[i][j]=='@'){ if(chmin(min_dist,abs(x-i)+abs(y-j))){ res = make_pair(i,j); } } } assert(min_dist!=inf); return res; } //最も近い店に移動する void move_nearest_shop(){ pii p = nearest_shop(); move(p); } //一手進める void one_step(){ move_nearest_shop(); assert(A[nowx][nowy]=='@'); double best_eval = (double)INF+1; State best_state; while(best_eval>=(double)INF){ for(int i=0;i<m;i++){ State state = *this; state.buy(i); state.use(i); double eval = diff_eval(*this,state); if(chmin(best_eval,eval)){ best_state = state; } } for(int iter=0;iter<5000;iter++){ int num = 1; vi i(num),j(num),k(num); for(int t=0;t<num;t++){ i[t] = randInt(0,n-1); j[t] = randInt(0,n-1); k[t] = randInt(0,m-1); } State state = *this; for(int t=0;t<num;t++){ state.buy(k[t]); } for(int t=0;t<num;t++){ state.move(i[t],j[t]); state.use(k[t]); } double eval = diff_eval(*this,state); if(chmin(best_eval,eval)){ best_state = state; } } } /* for(int i=0;i<n;i++)for(int j=0;j<n;j++){ for(int k=0;k<m;k++){ State state = *this; state.buy(k); state.move(i,j); state.use(k); int broken_building = building - state.building; int usecost = state.cost - cost; int eval; if(broken_building==0) eval = inf; else if(state.shop==0 && state.building!=0) eval = inf; else{ eval = usecost/broken_building; } if(chmin(best_eval,eval)){ best_i = i; best_j = j; best_k = k; } } } */ *this = best_state; } //爆破場所を決め打ちして1手進める void one_step2(){ int i,j; while(!que.empty()){ tie(i,j) = que.front(); que.pop(); if(A[i][j]!='.') break; } if(A[i][j]=='.') return; double best_eval = (double)INF+1; int best_k,best_t; while(best_eval>=(double)INF){ int max_iter = 5000; for(int iter=0;iter<max_iter;iter++){ //爆弾の種類とどの爆風で破壊するか決める int k,t,explode_x,explode_y; do{ k = randInt(0,m-1); t = randInt(0,l[k]); //爆破場所 explode_x = i-a[k][t]; explode_y = j-b[k][t]; }while(!is_valid(explode_x,explode_y)); //爆破したらどうなるか int broken_building; int broken_shop; bool center_shop_broken; tie(broken_building,broken_shop,center_shop_broken) = use_simulate(k,explode_x,explode_y); if(broken_building==0) continue; //コストシミュレーション auto shop_pos = nearest_shop(explode_x,explode_y); int use_cost = 0; //shopまでの移動 use_cost += smart_route(nowx,nowy,shop_pos.first,shop_pos.second).first; //shopでの購入 use_cost += c[k]; //shopから爆破場所までの移動 use_cost += 4*smart_route(shop_pos.first,shop_pos.second,explode_x,explode_y).first; double eval = eval_func(use_cost,broken_building,broken_shop,center_shop_broken); if(chmin(best_eval,eval)){ best_k = k; best_t = t; } } } int best_explode_x = i-a[best_k][best_t]; int best_explode_y = j-b[best_k][best_t]; auto shop_pos = nearest_shop(best_explode_x,best_explode_y); move(shop_pos.first,shop_pos.second); buy(best_k); move(best_explode_x,best_explode_y); use(best_k); } //シミュレーション結果で評価 double eval_func(double usecost,double broken_building,double broken_shop,bool center_shop_broken){ if(broken_building==0) return (double)INF; else if(shop==broken_shop && building>broken_building) return (double)INF; else{ double eval = (double)usecost/(double)broken_building; if(center_shop_broken) eval *= 10; return eval; } } //差分評価 double diff_eval(State now, State nex){ int broken_building = now.building - nex.building; int usecost = nex.cost - now.cost; if(broken_building==0) return (double)INF; else if(nex.shop==0 && nex.building!=0) return (double)INF; else{ double eval = (double)usecost/(double)broken_building; if(nex.A[nex.center_shop_x][nex.center_shop_y]!='@') eval *= 10; return eval; } } //出力 void output(){ cout<<hist.size()<<endl; for(auto p:hist){ if(p.first==1){ cout<<1<<" "; if(p.second==0) cout<<"U"; if(p.second==1) cout<<"D"; if(p.second==2) cout<<"L"; if(p.second==3) cout<<"R"; cout<<'\n'; } else cout<<p.first<<" "<<p.second+1<<"\n"; } } }; struct Solve{ vector<vector<char>> A; void IN(){ cin.tie(nullptr); ios::sync_with_stdio(false); cin>>n>>m; A.resize(n); for(int i=0;i<n;i++){ A[i].resize(n); for(int j=0;j<n;j++){ cin>>A[i][j]; } } for(int i=0;i<m;i++){ cin>>c[i]>>l[i]; for(int j=0;j<l[i];j++){ int tmpa,tmpb; cin>>tmpa>>tmpb; a[i].emplace_back(tmpa); b[i].emplace_back(tmpb); } } } void solve(){ Bombplan bombplan(A); cerr<<bombplan.eval()<<endl; State state(A); while(state.building>0){ state.one_step2(); cerr<<state.building<<" "<<state.shop<<" "<<state.cost<<'\n'; } cerr<<"buy_cost:"<<state.buy_cost<<endl; cerr<<"move_cost:"<<state.move_cost<<endl; cerr<<"total_cost:"<<state.cost<<endl; state.output(); } /* void sa(){ Bombplan bombplan(A); double start_temp = 1; double end_tmp = 1; double start = get_time(); cerr<<"start_sa\n"; int iter=0; int trans_cnt = 0; while(true){ iter++; double now_time = get_time(); if(now_time-start>1900) break; Bombplan new_bombplan = bombplan; new_bombplan.random_trans_plan(); int pre_score = bombplan.eval(); int new_score = new_bombplan.eval(); //温度関数 double temp = start_temp + (end_tmp-start_temp)*(now_time-start)/1900; //遷移確率関数 double prob = exp((pre_score-new_score)/temp); //遷移回数 if(prob>randDouble(0,1)){ //遷移 bombplan = new_bombplan; trans_cnt++; if(iter%500==1){ cerr<<"iter:"<<iter<<endl; cerr<<"trans_cnt:"<<trans_cnt<<endl; cerr<<"time:"<<now_time-start<<"ms\n"; cerr<<"score:"<<new_score<<endl; } } else{ if(iter%500==1){ cerr<<"iter:"<<iter<<endl; cerr<<"trans_cnt:"<<trans_cnt<<endl; cerr<<"time:"<<now_time-start<<"ms\n"; cerr<<"score:"<<pre_score<<endl; } } } best_plan = bombplan; } */ }; int main(){ start_time = get_time(); Solve solve; solve.IN(); solve.solve(); cerr<<"time:"<<get_time()-start_time<<"ms\n"; }