kmjp's blog

競技プログラミング参加記です

Codeforces #724 Div2 : F. Omkar and Akmar

最終問の割にコードは短い。
https://codeforces.com/contest/1536/problem/F

問題

N個のマスが円周状に並んでいる。
これを用いて2人でターン制のゲームを行う。

自ターンでは、空きマスを1つ選び、AかBの文字を埋める。
ただし、同じ文字が2つ並ぶ埋め方をしてはならない。

ゲームの展開は何通りあるか。

解法

もしN個中M個のマスが埋まった状態で終わったとする。

  • N=Mの場合、ABABAB....と埋まるので順番を無視すると2通り。順番がN!通りなので、解は2*N!通り。
  • M<Nの場合、まず2M≧Nである必要がある。この時、ABABAB...の各文字の間に、空きますが0個か1個入った状態である。
    • なので、1番目のマスが空いているケースと開いていないケースを考えると、2*M!*(Binom(M,N-M)+Binom(M-1,N-M-1))通り。
int N;
const ll mo=1000000007;
const int NUM_=1400001;
static ll fact[NUM_+1],factr[NUM_+1],inv[NUM_+1];
ll comb(ll N_, ll C_) {
	if(C_<0 || C_>N_) return 0;
	return factr[C_]*fact[N_]%mo*factr[N_-C_]%mo;
}


void solve() {
	int i,j,k,l,r,x,y; string s;

	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;
	
	cin>>N;
	ll ret=0;
	for(x=0;x<=N;x+=2) {
		if(x*2<N) continue;
		if(x==N) {
			ret+=2*fact[N];
		}
		else {
			ret+=2*fact[x]*(comb(x,N-x)+comb(x-1,N-x-1))%mo;
		}
	}
	cout<<ret%mo<<endl;
}

まとめ

この回全体的に簡単だったっぽい?