题目:
https://www.luogu.org/problemnew/show/P3746
分析:
设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示在
m
m
o
d
k
=
j
m\ mod\ k=j
m mod k=j的
(
i
m
)
\binom{i}{m}
(mi)的和。
转移显然,
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
+
f
[
i
−
1
]
[
(
j
+
k
−
1
)
m
o
d
k
]
f[i][j]=f[i-1][j]+f[i-1][(j+k-1)\ mod\ k]
f[i][j]=f[i−1][j]+f[i−1][(j+k−1) mod k]
因为
k
k
k较小,可以构造出矩阵进行递推,其中
f
[
0
]
[
0
]
=
1
f[0][0]=1
f[0][0]=1。
代码:
// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cmath>
#define LL long long
const int N=57;
using namespace std;
LL n,mod;
int k,r;
struct matrix{
int n,m;
LL a[N][N];
}A,B,C;
matrix operator *(matrix a,matrix b)
{
matrix c;
c.n=a.n,c.m=b.m;
for (int i=1;i<=c.n;i++)
{
for (int j=1;j<=c.m;j++) c.a[i][j]=0;
}
for (int k=1;k<=a.m;k++)
{
for (int i=1;i<=c.n;i++)
{
for (int j=1;j<=c.m;j++)
{
c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j]%mod)%mod;
}
}
}
return c;
}
void ksm(LL p)
{
if (p==0) return;
ksm(p/2);
B=B*B;
if (p&1) B=B*A;
}
int main()
{
scanf("%lld%lld%d%d",&n,&mod,&k,&r);
A.n=A.m=B.n=B.m=k;
for (int i=1;i<=k;i++)
{
A.a[i][i]++;
if (i==1) A.a[i][k]++;
else A.a[i][i-1]++;
B.a[i][i]=1;
}
ksm(n*(LL)k);
C.n=1,C.m=k;
C.a[1][1]=1;
C=C*B;
printf("%lld\n",C.a[1][r+1]);
}