cafelier のSRM参加記録です。コンテスト中に考えてたことを執拗に全部書き残すとどうなるだろうかという試み本番中にこういうコードが書きたかったなあ、という後で書いた反省コードを書き残す試み
スパムが来たのでしばらくコメント欄をはてなユーザ限定にしています、すみません、
SRM | |
TCO09 Round1 の成績・ソース (要ログイン) : AC/-/- : もう通ればいいんだ…
あとで | |
わーいDPだ
class KthProbableElement { public: double probability(int M, int lowerBound, int upperBound, int N, int K) { double dp1[101][101]={0}, dp2[101][101], (*P)[101]=dp1, (*Q)[101]=dp2; P[0][0] = 1.0; for(int i=0; i<M; ++i) { memset( Q, 0, sizeof(double)*101*101 ); for(int a=0; a<=i; ++a) for(int b=0; a+b<=i; ++b) { Q[a+1][b] += P[a][b] * (N-lowerBound) / (upperBound-lowerBound+1); Q[a][b+1] += P[a][b] * 1 / (upperBound-lowerBound+1); Q[a][b] += P[a][b] * (upperBound-N) / (upperBound-lowerBound+1); } swap(P, Q); } double p = 0.0; for(int a=0; a<=M; ++a) for(int b=0; a+b<=M; ++b) if( a<K && K<=a+b ) p += P[a][b]; return p; } };
P[a][b] @ i == M個中i個目まで値を選んだとき、N未満の値がa個、Nがb個、(Nより大きいのがi-a-b個)、になっている確率。なんでこれが時間内で書けないかな自分は…
あとで | |
普段mod演算は念のためlong longでやってるのだけど、それだとTLEした。intに変えて通しました。これは本番でいくら時間があっても気づけなかった予感。
static const int MODVAL = 1000000007; int ADD(int x, int y) { return (x+y)%MODVAL; } int SUB(int x, int y) { return (x-y+MODVAL)%MODVAL; } class Unicorn { public: int countWays(int R, int C, int L, int seed, string word) { // input... char B[300][300]; { int x = seed; int d = (65535 / L)+1; for (int r=0; r<R; r++) for (int c=0; c<C; c++) { x = (x * 25173 + 13849) % 65536; B[r][c] = (65+(x / d)); } } // solve vector<int> cnt(C*R); for(int r=0; r<R; ++r) for(int c=0; c<C; ++c) if( B[r][c] == word[0] ) cnt[r*C+c] = 1; for(int i=1; i<word.size(); ++i) { int total_cnt = 0; vector<int> c_cnt(C); vector<int> r_cnt(R); for(int r=0; r<R; ++r) for(int c=0; c<C; ++c) r_cnt[r] = ADD( r_cnt[r], cnt[r*C+c]), c_cnt[c] = ADD( c_cnt[c], cnt[r*C+c]), total_cnt = ADD(total_cnt, cnt[r*C+c]); vector<int> cnt2(C*R); for(int r=0; r<R; ++r) for(int c=0; c<C; ++c) if( B[r][c] == word[i] ) { int x = total_cnt; for(int rr=r-1; rr<=r+1; ++rr) if(0<=rr && rr<R) x = SUB(x, r_cnt[rr]); for(int cc=c-1; cc<=c+1; ++cc) if(0<=cc && cc<C) x = SUB(x, c_cnt[cc]); for(int rr=r-1; rr<=r+1; ++rr) if(0<=rr && rr<R) for(int cc=c-1; cc<=c+1; ++cc) if(0<=cc && cc<C) x = ADD(x, cnt[rr*C+cc]); for(int rr=r-2; rr<=r+2; rr+=4) if(0<=rr && rr<R) for(int cc=c-2; cc<=c+2; cc+=4) if(0<=cc && cc<C) x = SUB(x, cnt[rr*C+cc]); cnt2[r*C+c] = x; } cnt.swap(cnt2); } int live = 0; for(int r=0; r<R; ++r) for(int c=0; c<C; ++c) live = ADD(live, cnt[r*C+c]); return live; } };
ユニコーンのいけないところを列単位行単位でまとめておいて数えるとO(1)でひとつの遷移を計算できる
presented by cafelier/k.inaba under