実際テストケース233で失敗したら嫌な気分になるよね。
http://codeforces.com/contest/1261/problem/D2
問題
K択問題がN個あるとし、その解が与えられる。
この回答を1つrotateした場合を考える。
K択問題N個の解答はK^N通り考えられるが、正答がrotateした方が正答数が増えるのは何通りか。
解法
rotateしてもしなくても解が変わらない部分は無視し、そうでない場所がD問あったとする。
これらD問に対し取りえる解は以下のいずれかである。
- rotate前の正答
- rotate後の正答
- いずれでも正答でない残り(K-2)通り
D問中前者のいずれかを取る問題がi問だとする。
i問で後者を選ぶのはfloor(i/2)より多ければよいので、それらを数え上げればよい。
int N,K; int H[202020]; const ll mo=998244353; ll comb(ll N_, ll C_) { const int NUM_=400001; static ll fact[NUM_+1],factr[NUM_+1],inv[NUM_+1]; if (fact[0]==0) { inv[1]=fact[0]=factr[0]=1; for (int i=2;i<=NUM_;++i) inv[i] = inv[mo % i] * (mo - mo / i) % mo; for (int i=1;i<=NUM_;++i) fact[i]=fact[i-1]*i%mo, factr[i]=factr[i-1]*inv[i]%mo; } if(C_<0 || C_>N_) return 0; return factr[C_]*fact[N_]%mo*factr[N_-C_]%mo; } ll from[4020]; ll to[4020]; ll P[202020]; ll P2[202020]; void solve() { int i,j,k,l,r,x,y; string s; cin>>N>>K; FOR(i,N) { cin>>H[i]; H[i]--; } H[N]=H[0]; P[0]=1; P2[0]=1; FOR(i,N+1) { P[i+1]=P[i]*(K-2)%mo; P2[i+1]=P2[i]*2%mo; } int same=0,dif=0; FOR(i,N) { if(H[i]==H[i+1]) same++; else dif++; } ll ret=0; for(i=0;i<=dif;i++) { int either=dif-i; ll pat; if(either%2==1) { pat=P2[either-1]; } else { pat=P2[either]+mo-comb(either,either/2); pat=pat%mo*((mo+1)/2)%mo; } (ret+=P[i]*pat%mo*comb(dif,i))%=mo; } ret%=mo; FOR(i,same) ret=ret*K%mo; cout<<ret%mo<<endl; }
まとめ
Div1のDとしては簡単な気がする。