Google Code Jam 2013 Round1B
お酒の力を借りて本気出した(?)
- -
A : Osmos
- 制約を何となくしか見てなくて、N≦10^6 と勘違いする。
- DPするだけかと思いきやそれは無理そう(と思い込む)。
- 削除操作を途中に挟んでも無意味そう。
- でかくする→マージ出来ないの削除 をシミュレーションして最小値とれば良い?
- small通ったのでlargeにも投げたら通った。
#include <iostream> #include <vector> #include <algorithm> #include <cstdio> using namespace std; int main(){ int T; cin >> T; long long A; int N; for(int test=1;test<=T;test++){ cin >> A >> N; vector<int> v; for(int i=0;i<N;i++){ int t; cin >> t; v.push_back(t); } sort(v.begin(), v.end()); int res = N; int cnt = 0; if(A > 1){ for(int i=0;i<N;i++){ res = min(res, cnt+N-i); while(v[i] >= A){ A += A-1; cnt++; } A += v[i]; } res = min(res, cnt); } printf("Case #%d: %d\n", test, res); } }
B : Falling Diamonds
- smallはDPおkで、largeが式立てないといけない感じか…?と思いながら読んだ。
- …ところ、制約を眺めたらlargeがDPで良さそうだったので、書いた。
- largeを実行したらセグフォしたのでオワタと思った。
- けど、上限の見積もりが適当だったため、配列を倍にしたら実行出来たので投げた。
- 奇跡的に通った。
#include <iostream> #include <vector> #include <cstdio> #include <algorithm> using namespace std; double dp[2000][2000]; double solve(int N, int X, int Y){ int place = (abs(X)+abs(Y))/2; int sum = 0; for(int i=0;i<place;i++){ sum += 4*i+1; if(sum > N) return 0; } if(sum > N) return 0; if(sum + 4*place+1 <= N) return 1.0; for(int i=0;i<2000;i++) for(int j=0;j<2000;j++) dp[i][j] = 0; dp[0][0] = 1.0; for(int i=0;i<=2*place;i++){ for(int j=0;j<=2*place;j++){ if(i==2*place&&j==2*place) continue; if(i==2*place){ dp[i][j+1] += dp[i][j]; } else if(j==2*place){ dp[i+1][j] += dp[i][j]; } else { dp[i][j+1] += 0.5*dp[i][j]; dp[i+1][j] += 0.5*dp[i][j]; } } } int lest = N-sum; double res = 0; for(int i=abs(Y)+1;i<=lest;i++){ if(i > 2*place || lest-i > 2*place) continue; res += dp[i][lest-i]; } return res; } int main(){ int T; cin >> T; int N, X, Y; for(int test=1;test<=T;test++){ cin >> N >> X >> Y; printf("Case #%d: %.8lf\n", test, solve(N, X, Y)); } }
C : Garbled Email
- 辞書のサイズ見てやばそうと思った(小並感)
- DPを適当に高速化しておけばsmallくらい通るんじゃね?という気持ちになる。
- DPが適当すぎてsmallで2WA。
- 初回提出などINFがreturnされてたほどの体たらく
- largeを考えるのが面倒になり、思い出実行して寝ることに決める。
- 歯みがきして戻ってきたら驚くべきことに実行が終わってた。
- せっかくなので思い出サブミットして寝た。
- 起きたら通ってて驚いた。
#include <iostream> #include <fstream> #include <vector> #include <string> #include <cstring> #include <cstdio> using namespace std; int mem[5][4001]; int main(){ int T; cin >> T; vector<string> vs; ifstream fin("garbled_email_dictionary.txt"); string str; while(fin >> str) vs.push_back(str); for(int test=1;test<=T;test++){ memset(mem, -1, sizeof(mem)); mem[4][0] = 0; cin >> str; for(int i=0;i<str.size();i++){ for(int j=0;j<vs.size();j++){ int first = 1000, last = -100; int cnt = 0; bool ok = true; if(i+vs[j].size() > str.size()) continue; for(int k=0;k<vs[j].size();k++){ if(vs[j][k] != str[i+k]){ cnt++; if(last == -100) first = k; else if(k-last < 5){ ok = false; break; } last = k; } } if(!ok) continue; for(int k=0;k<5;k++){ if(mem[k][i] == -1) continue; if(first < 4-k) continue; int nm = min(4, last != -100 ? (int)vs[j].size()-1-last : k+(int)vs[j].size()); int np = i+vs[j].size(); if(mem[nm][np] == -1) mem[nm][np] = mem[k][i] + cnt; else mem[nm][np] = min(mem[nm][np], mem[k][i]+cnt); } } } int res = 1000000; for(int i=0;i<5;i++){ if(mem[i][str.size()] == -1) continue; res = min(res, mem[i][str.size()]); } printf("Case #%d: %d\n", test, res); } }
- -
Rank 18 : /oo/oo/oo/ Score 100, Penalty 1:30:22
お酒飲んで思考停止してた部分がたまたま良い感じに働いた…んですかね。
何故か過去最高順位でしたが、怖いのでRound2はシラフでやると思います。