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

luogu

考虑组合数递推公式\(\binom{n}{m}=\binom{n-1}{m}+\binom{n-1}{m-1}\),然后代入原式,有

\(\sum_{i=0}^{\infty} \binom{nk}{ik+r}=\sum_{i=0}^{\infty} \binom{nk-1}{ik+r}+\sum_{i=0}^{\infty} \binom{nk-1}{ik+r-1}\)

\(f_{i,j}=\sum_{i=0}^{\infty} \binom{i}{ik+j}\),那么就会有\(f_{i,j}=f_{i-1,j}+f_{i-1,(j-1)\bmod k}\),就可以矩乘转移了.或者可以发现\(f_{i,j}=[x^j]((x+1)^i\pmod{x^k-1})\),使用倍增+FFT可以做到\(O(k\log n\log k)\)

#include<bits/stdc++.h>
#define LL long long
#define db double

using namespace std;
const int N=1e6+10;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
    return x*w;
}
int n,mod,k,r;
int fpow(int a,int b,int mod){int an=1;while(b){if(b&1) an=1ll*an*a%mod;a=1ll*a*a%mod,b>>=1;}return an;}
struct matrix
{
	int a[50][50];
	matrix(int az=0){memset(a,0,sizeof(a));for(int i=0;i<50;++i) a[i][i]=az;}
	matrix operator * (const matrix &bb) const
	{
		matrix an;
		for(int i=0;i<k;++i)				
			for(int l=0;l<k;++l)
				for(int j=0;j<k;++j)
					an.a[i][j]=(1ll*a[i][l]*bb.a[l][j]+an.a[i][j])%mod;
		return an;
	}
}aa,bb;

int main()
{
	n=rd(),mod=rd(),k=rd(),r=rd();
	for(int i=0;i<k;++i) ++bb.a[i][i],++bb.a[i][(i+1)%k];
	aa.a[0][0]=1;
	LL rs=1ll*n*k;
	while(rs)
	{
		if(rs&1) aa=aa*bb;
		bb=bb*bb,rs>>=1;
	}
	printf("%d\n",aa.a[0][r]);
	return 0;
}
posted @ 2020-05-20 22:35  ✡smy✡  阅读(145)  评论(0编辑  收藏  举报