P3746 [六省联考2017]组合数问题

P3746 [六省联考2017]组合数问题

\(dp_{i,j}\)表示前\(i\)个物品,取的物品模\(k\)等于\(r\),则\(dp_{i,j}=dp_{i-1,(j-1+k)\%k}+dp_{i-1,j}\)

\(dp_{i,0},dp_{i,1},dp_{i,2}.....dp_{i,k-1}\) \(\Longrightarrow\) \(dp_{i+1,0},dp_{i+1,1},dp_{i+1,2}.....dp_{i+1,k-1}\)

仔细想想,你能构造出矩阵的

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const LL maxn=100;
inline LL Read(){
	LL x=0,f=1; char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') f=-1; c=getchar();
	}
	while(c>='0'&&c<='9')
		x=(x<<3)+(x<<1)+c-'0',c=getchar();
	return x*f;
}
struct mat{
	LL m[maxn][maxn];
}rt,a,b;
LL n,MOD,K,r;
inline mat Mul(const mat &x,const mat &y){
	mat res;
    memset(res.m,0,sizeof(res.m));
	for(LL i=0;i<=K-1;++i)
	    for(LL j=0;j<=K-1;++j)
	        for(LL k=0;k<=K-1;++k)
	            res.m[i][j]=(res.m[i][j]+x.m[i][k]*y.m[k][j]%MOD)%MOD;
	return res;
}
inline void Pow(LL mi){
	while(mi){
		if(mi&1)
		    a=Mul(a,b);
		b=Mul(b,b);
		mi>>=1;
	}
}
int main(){
	n=Read(),MOD=Read(),K=Read(),r=Read();
	for(LL i=0;i<=K-2;++i)
	    b.m[i][i]=b.m[i][i+1]=1;
	++b.m[K-1][0],++b.m[K-1][K-1];
	for(LL i=0;i<=K-1;++i)
	    a.m[i][i]=1;
	Pow(n*K);
	rt.m[0][0]=1;
	rt=Mul(rt,a);
	printf("%lld",rt.m[0][r]);
	return 0;
}
posted @ 2018-12-27 13:52  y2823774827y  阅读(175)  评论(0编辑  收藏  举报