Particle

競技プログラミングについての雑記

SRM 644 Div1 Medium MakingTournament

実験すると、K=1 のときは、フィボナッチ数列になる。
K>1 のときは、2^K +1 項間漸化式になりそうなので、最初の 2^K +1 項あたりまでを愚直に計算すると、行列を復元することができる。

というのを実装したら通った。直感的には正しいことが分かるが、ちゃんと証明して解きたい。

#define M 300
ll f[7][M], g[7][M];

ll pow_mod(ll a, ll r, ll m){
	ll x = 1;
	while(r){
		if(r&1) (x*=a)%=m;
		(a*=a)%=m;
		r>>=1;
	}
	return x;
}

vector<ll> mul(vector<vector<ll>> &A, vector<ll> &x){
	int n = x.size();
	vector<ll> y(n, 0);
	rep(i, n) rep(j, n) (y[i]+=A[i][j]*x[j])%=mod;
	return y;
}

void mul(vector<vector<ll>> &A){
	vector<vector<ll>> B(A);
	int n = A.size();
	A = vector<vector<ll>>(n, vector<ll>(n, 0));
	rep(k, n) rep(i, n) rep(j, n) (A[i][j]+=B[i][k]*B[k][j])%=mod;
}

class MakingTournament {
	public:
	int howManyWays(long long N, int K) {
		mset(f, 0); mset(g, 0);
		rep(i, M) g[0][i] = 1;
		g[0][1] = 0;
		f[0][0] = 1;
		for(ll i = 2; i < M; i++) f[0][i] = (f[0][i-1]+f[0][i-2])%mod;

		for(ll k = 1; k < 6; k++){
			rep(i, M) g[k][i] = (f[k-1][i]-g[k-1][i]+mod)%mod;
			f[k][0] = 1;
			rep(i, M) rep(j, i) (f[k][i]+=f[k][j]*g[k][i-j])%=mod;
		}
		ll m = 1<<K;
		vector<vector<ll>> A(m, vector<ll>(m, 0));
		rep(i, m-1) A[i+1][i] = 1;
		rep(i, m){
			ll sum = 0;
			rep(j, m) (sum+=f[K-1][i+j+1]*A[0][m-j-1])%=mod;
			A[0][i] = (f[K-1][i+m+1]-sum+mod)%mod;
		}
		vector<ll> x(m, 0);
		x[0] = 1;
		N--;
		while(N){
			if(N%2) x = mul(A, x);
			mul(A);
			N>>=1;
		}
		return (x[m-1]+mod)%mod;
	}
};