题意:链接
求 ( ∑ i = 0 ∞ C n k i k + r ) m o d p (\sum_{i=0}^{\infty} C_{nk}^{ik+r}) \mod p (∑i=0∞Cnkik+r)modp
思路:
发现此题推二项式定理并没有什么用…
考虑这个式子的意义:在
N
=
n
k
N=nk
N=nk个物品中选模
k
k
k余
r
r
r个物品的方案数之和。
设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示在
i
i
i个物品中选模
k
k
k余
j
j
j个物品的方案数之和,有
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
(
j
−
1
+
k
)
%
k
]
+
d
p
[
i
−
1
]
[
j
]
dp[i][j]=dp[i-1][(j-1+k)\%k]+dp[i-1][j]
dp[i][j]=dp[i−1][(j−1+k)%k]+dp[i−1][j](选或不选第i个物品)
所以用矩阵快速幂来优化。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 50
#define LL long long
int MO,r,K;
LL n;
struct matrix
{
int a[MAXN][MAXN];
matrix()
{
for(int i=0;i<K;i++)
for(int j=0;j<K;j++)
a[i][j]=0;
}
}f,ans,g;
matrix operator * (matrix a,matrix b)
{
matrix ret;
for(int i=0;i<K;i++)
for(int j=0;j<K;j++)
ret.a[i][j]=0;
for(int i=0;i<K;i++)
for(int j=0;j<K;j++)
for(int k=0;k<K;k++)
ret.a[i][j]=(ret.a[i][j]+1LL*a.a[i][k]*b.a[k][j]%MO)%MO;
return ret;
}
int main()
{
scanf("%lld%d%d%d",&n,&MO,&K,&r);
for(int i=0;i<K;i++)
f.a[i][i]++,f.a[(i-1+K)%K][i]++,ans.a[i][i]=1;
n=n*K;
while(n)
{
if(n&1) ans=ans*f;
f=f*f;
n>>=1;
}
printf("%d\n",ans.a[0][r]);
}