CF621E题解
题面
有
我们设
递推式也容易推出来:
但是,这样显然会 TLE。所以我们需要一些优化。
对于每一个
对于矩阵快速幂,这是一种好用的优化递推的算法。
首先,定义矩阵乘法:
对于一个
然后,因为矩阵乘法满足结合律,所以我们有了矩阵快速幂。矩阵快速幂的话就是把快速幂的板子套在矩阵上而已。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int n,b,x,k,a[50005];
struct M{
int a[100][100];//矩阵
M operator*(M t){//乘
M res;
for(int i=0;i<x;i++)for(int j=0;j<x;j++)res.a[i][j]=0;
for(int i=0;i<x;i++){
for(int j=0;j<x;j++){
for(int k=0;k<x;k++){
res.a[i][j]=(res.a[i][j]+a[i][k]*t.a[k][j]%mod)%mod;
}
}
}
return res;
}
M operator^(int k){//快速幂
M res,_=*this;
for(int i=0;i<x;i++)for(int j=0;j<x;j++)res.a[i][j]=(i==j);
while(k){
if(k&1)res=res*_;
_=_*_;
k>>=1;
}
return res;
}
}ans,base;
signed main()
{
scanf("%lld%lld%lld%lld",&n,&b,&k,&x);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=0;i<x;i++)for(int j=0;j<x;j++)ans.a[i][j]=0;
for(int i=0;i<x;i++)for(int j=0;j<x;j++)base.a[i][j]=0;
ans.a[0][0]=1;
for(int i=0;i<x;i++){
for(int j=1;j<=n;j++){
base.a[(i*10+a[j])%x][i]++;//求出转移式
}
}
ans=(base^(b))*ans;//推!
printf("%lld",ans.a[k][0]);
return 0;
}