给出n,b,k,x; 以及n个数 n<=1e5,b<=1e9,k,x<=100
给你一个盒子,盒子里面有n个数,全是1-9,
让你从盒子1,选一个数,盒子2选一个.....一共b个盒子,
这些盒子选出来的每一种方案都对应着一个数NUM,求num%x==k的方案数,对1e9+7取模
//设num=k*x+j,num%x=j, (10*num+d)%x=(10k*x+10j+d)%x=(10j+d)%x;
即知道前i-1个盒子时 余数为j的方案数,就能知道第i个盒子时,余数为(10j+d)%x的方案数的一个增量
//状态转移方程为 dp[i][(10*j+d)%x]+= dp[i-1][j]*(num[d]);
//显然,最终答案是 dp[b][k] , b太大,并且每次转移的操作是一样的,所以需要用矩阵快速幂优化
//我们把前i-1个数下的余数d为0~x-1的方案数写成一行
//每个状态i显然是一个x*1的矩阵,我们需要构造一个x*x的矩阵
//在前i-1个数时,余数为d的方案下,只要(d*10+num)%x== Dj,就表示这个d与num结合后,会对前i个数下的余数为Dj的情况有贡献
//那么就在系数矩阵的第Dj 列的 d行位置 加上num[1~9],从而构造出系数矩阵 :
for (i=0;i<x;i++)
{
for (j=1;j<=9;j++)
p.mat[i][(10*i+j)%x]+=num[j];//上一状态下余数为i的方案数,乘上num[j],便可以得到下一状态余数为(10*i+j)%x的方案数增量
}
初始化 条件为 初始矩阵DP的【0】【0】=1; // 余数为0的方案为1;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
struct Matrix
{
__int64 mat[105][105];
};
Matrix unit_matrix,p,dp ;
__int64 MAX=100;
__int64 mod=1e9+7;
Matrix mul(Matrix a, Matrix b) //矩阵相乘
{
Matrix res;
for(int i = 0; i < MAX; i++)
for(int j = 0; j < MAX; j++)
{
res.mat[i][j] = 0;
for(int t = 0; t < MAX; t++)
{
res.mat[i][j] += a.mat[i][t] * b.mat[t][j];
res.mat[i][j] %= mod;
}
}
return res;
}
Matrix pow_matrix(Matrix a, __int64 m) //矩阵快速幂
{
Matrix res = unit_matrix;
while(m != 0)
{
if(m & 1)
res = mul(res, a);
a = mul(a, a);
m >>= 1;
}
return res;
}
__int64 num[10];
int main()
{
__int64 i, j, t;
__int64 n,b,x,k;
scanf("%d%d%d%d",&n,&b,&k,&x);
__int64 xx;
for(i = 1; i<=n; i++)
{
scanf("%d",&xx);
num[xx]++;
}
//初始化单位矩阵
for(i = 0; i < x; i++) unit_matrix.mat[i][i] = 1;
for (i=0;i<x;i++)
{
for (j=1;j<=9;j++)
p.mat[i][(10*i+j)%x]+=num[j];//上一状态下余数为i的方案数,乘上num[j],便可以得到下一状态余数为(10*i+j)%x的方案数增量
}
dp.mat[0][0]=1;
dp=mul(dp,pow_matrix(p,b));
printf("%I64d\n",dp.mat[0][k]);
return 0;
}