3734 Blocks

問題概要

n個のタイルを赤、緑、青、黄の4色に塗る。
そのような塗り方のうち、赤と緑のタイルの枚数が偶数になるような塗り方は何通りか。
mod 10007で求めよ。


n≦10^9とする。

解法

4色の偶奇をそれぞれ1ビットで表わす。
i枚のタイルを偶奇jの状態で塗る塗り方をdp[i][j]とすると、
dp[i+1][j]=Σ{dp[i][k]|jとkが、一枚だけ偶奇が異なる}

という漸化式が立つのでDPができるが、nが大きいのでそのままやるとTLEする。


線形2項間漸化式は行列の掛け算に変換できるので、n乗を繰り返し二乗法で求めれば間に合う。

ソースコード

const int mod=10007;
struct M{
	int a[16][16];
	M operator*(const M &r){
		M ret;
		rep(i,16)rep(j,16){
			ret.a[i][j]=0;
			rep(k,16)ret.a[i][j]+=a[i][k]*r.a[k][j];
			ret.a[i][j]%=mod;
		}
		return ret;
	}
};
int bit(int b){
	int r=0;
	for(;b;b&=b-1)r++;
	return r;
}
int main()
{
	int n,T; scanf("%d",&T);
	rep(U,T){
		scanf("%d",&n);
		M x,r;
		rep(i,16)rep(j,16)x.a[i][j]=i==j,r.a[i][j]=bit(i^j)==1;
		for(int i=n;i;i/=2){
			if(i&1)x=x*r;
			r=r*r;
		}
		int ans=0; rep(i,4)ans+=x.a[0][i];
		printf("%d\n",ans%mod);
	}
	return 0;
}