题目大意:有m (m<=1e9) 个相同的块,每个块里边有n个数,每个数的范围是1-9,从每个块里边取出来一个数组成一个数,让你求组成的方案中
被x取模后,值为k的方案数。(1<=k<x<=100)
思路:刚开始把m看成了1e5,写了一发数位dp,果断RE,然后我在考虑从当块前状态转移到下一个块状态模数的改变都用的是一套规则,因为
每个块里面的数字都是一样的,那么我们就可以很开心地构造出一个x*x的矩阵进行快速幂啦。
#include<bits/stdc++.h> #define read(x) scanf("%d",&x) #define ll long long using namespace std; const int mod=1e9+7; const int N=105; int cnt[10],n,b,k,x; struct node { node(int _row=0,int _col=0) { memset(a,0,sizeof(a)); row=_row; col=_col; } int row,col; ll a[N][N]; }; node mul(node x,node y) { node ans; ans.row=x.row,ans.col=y.col; for(int i=0;i<x.row;i++) for(int j=0;j<y.row;j++) for(int k=0;k<y.col;k++) ans.a[i][k]=(ans.a[i][k]+x.a[i][j]*y.a[j][k])%mod; return ans; } node quick_mul(node x,int n) { node ans; ans.row=x.row; ans.col=x.col; for(int i=0;i<ans.row;i++) ans.a[i][i]=1; while(n) { if(n&1) ans=mul(ans,x); x=mul(x,x); n>>=1; } return ans; } int main() { read(n); read(b); read(k); read(x); for(int i=1;i<=n;i++) { int p; read(p); cnt[p]++; } node A(x,x); for(int i=0;i<x;i++) { for(int j=0;j<x;j++) { for(int u=1;u<=9;u++) { int nx=(j*10+u)%x; if(nx!=i) continue; A.a[i][j]+=cnt[u]; } } } A=quick_mul(A,b); printf("%lld\n",A.a[k][0]); return 0; }