Codeforces 336D Vasily the Bear and Beautiful Strings
問題
01からなる文字列で、0がn個1がm個ちょうど含まれているものを考える。
この文字列に対して、以下の操作を繰り返した後で、最後にgになるものの個数を求めよ。
操作:
文字列が1文字になっていたら終了
末尾が00のとき、1に置き換える
末尾が01のとき、0に置き換える
末尾が10のとき、0に置き換える
末尾が11のとき、0に置き換える
制約条件
n, m≦10^5
gは0または1
方針
0がn個, 1がm個で、最後に0になる文字列の個数をa(n, m)、
最後に1になる文字列の個数をb(n, m)と置く。
すると、b(n, m) = a(n-1, m)である。
(評価して1になる文字列は、最後の1文字が0で、それ以外の評価は0になるしかない)
また、a(n, m) + b(n, m) = C(n + m, n)であるので、
a(n, m) = C(n + m, n) - b(n, m) = C(n + m, n) - a(n - 1, m)
という漸化式ができる。
これを使ってnが0になるまでnを減らせば、a(0, m)はO(1)で計算できるので、
結局O(n)でa(n, m)が計算できる。
ソースコード
const int mod = (int)1e9 + 7; ll fact[220000]; ll pw(ll n, ll m){ ll res = 1; for(; m; m >>= 1){ if(m & 1) res = res * n % mod; n = n * n % mod; } return res; } ll inv(ll n){ return pw(n, mod - 2); } ll C(ll n, ll m){ return fact[n] * inv(fact[m]) % mod * inv(fact[n - m]) % mod; } ll calc(int n, int m){ if(n == 1 && m == 0) return 1; if(n == 0) return m == 1 ? 0 : 1; return (C(n + m, n) - calc(n - 1, m) + mod) % mod; } int main(){ fact[0] = 1; rep(i, 220000-1) fact[i + 1] = fact[i] * (i + 1) % mod; int n, m, g; cin >> n >> m >> g; cout << (g ? (C(n + m, n) - calc(n, m) + mod) % mod : calc(n, m)) << endl; return 0; }