TopCoder SRM 449 Div1 Hard StairsColoring

問題

n段の階段があり、ちょうどn枚の長方形の板でできている。
長方形の板には重なりやはみだしがない。
このようにして作れる階段を全部つくり、階段を(一つの階段は一色で)それぞれk色のどれかで塗る。


このようにして出来上がるものは何通りあるか、mod 1000000123で求めよ。

制約条件

n, k≦10^9

方針

n段の階段の作り方について漸化式を立てる。
これは、大きい長方形を決めることが()を決めることに対応するので、
長さ2nの括弧からなる、括弧の対応する文字列の個数に等しい。
これはC(2n, n) / (n+1)!個である。


これをc(n)とすると、k^c(n)をmod 1000000123で求めたい。
1000000123は素数なので、フェルマーの小定理より、k^xは周期1000000122で循環する。


つまり、c(n)をmod 1000000122で求めればいいことになる。
1000000122を素因数分解して、それぞれの素因数についてのmodでc(n)を求めて、
中国剰余定理を使えばc(n)がmod 1000000122で求まる。


あとはk^xを繰り返し二乗法でmod 1000000123で求めればいい。

ソースコード

ll fact[10000];
ll extgcd(ll a, ll b, ll &x, ll &y){
	ll d = a;
	if(b){
		d = extgcd(b, a % b, y, x);
		y -= a/b * x;
	}
	else x = 1, y = 0;
	return d;
}
ll mod_inverse(ll a, ll m){
	ll x, y;
	extgcd(a, m, x, y);
	return (m + x%m) % m;
}
ll mod_fact(ll n, ll p, int &e){
	e = 0;
	if(n == 0) return 1;
	ll res = mod_fact(n/p, p, e);
	e += n/p;
	
	if(n/p % 2) return res * (p - fact[n%p]) % p;
	return res * fact[n%p] % p;
}
int calc(ll n, ll p){
	int e1, e2, e3;
	ll a1 = mod_fact(2*n, p, e1), a2 = mod_fact(n+1, p, e2), a3 = mod_fact(n, p, e3);
	if(e1 > e2 + e3) return 0;
	return a1 * mod_inverse(a2 * a3 % p, p) % p;
}

bool linear_congruence(const vector<ll> &A, const vector<ll> &B, const vector<ll> &M,
	ll &x, ll &m){
	x = 0; m = 1;
	
	rep(i,A.size()){
		ll a = A[i] * m, b = B[i] - A[i] * x, d = __gcd(M[i], a);
		if(b % d) return 0;
		ll t = b /d * mod_inverse(a/d, M[i]/d) % (M[i] / d);
		x = x + m * t;
		m *= M[i] / d;
	}
	x = (x + m) % m;
	return 1;
}

class StairsColoring {
  public:
  int coloringCount(int N, int K) {
		int ps[] = {2, 3, 11, 2089, 7253};
		vector<ll> a, b, m;
		rep(i,5){
			fact[0] = 1;
			rep(j, ps[i]) fact[j+1] = fact[j] * (j+1) % ps[i];
			b.pb(calc(N, ps[i]));
			m.pb(ps[i]);
			a.pb(1);
		}
		ll x, M;
		linear_congruence(a, b, m, x, M);
		dbg(x); dbg(M);
		rep(i, 5){
			cerr << a[i] << ", " << b[i] << ", " << m[i] << endl;
		}
		M++;
		ll ans = 1, y = K;
		for(; x; x /= 2){
			if(x & 1) ans = ans * y % M;
			y = y * y % M;
		}
		return ans;
  }
}: