Codeforces Round #341 (Div. 2)E(矩阵快速幂优化dp,好题)

2/10/2017来源:ASP.NET技巧人气:746

题目链接 E. Wet Shark and Blocks time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output

There are b blocks of digits. Each one consisting of the same n digits, which are given to you in the input. Wet Shark must choose exactly one digit from each block and concatenate all of those digits together to form one large integer. For example, if he chooses digit 1 from the first block and digit 2 from the second block, he gets the integer 12. 

Wet Shark then takes this number modulo x. Please, tell him how many ways he can choose one digit from each block so that he gets exactly k as the final result. As this number may be too large, PRint it modulo 109 + 7.

Note, that the number of ways to choose some digit in the block is equal to the number of it's occurrences. For example, there are 3 ways to choose digit 5 from block 3 5 6 7 8 9 5 1 1 1 1 5.

Input

The first line of the input contains four space-separated integers, nbk and x (2 ≤ n ≤ 50 000, 1 ≤ b ≤ 109, 0 ≤ k < x ≤ 100, x ≥ 2) — the number of digits in one block, the number of blocks, interesting remainder modulo x and modulo x itself.

The next line contains n space separated integers ai (1 ≤ ai ≤ 9), that give the digits contained in each block.

Output

Print the number of ways to pick exactly one digit from each blocks, such that the resulting integer equals k modulo x.

Examples input
12 1 5 10
3 5 6 7 8 9 5 1 1 1 1 5




output
3




input
3 2 1 2
6 2 2




output
0




input
3 2 1 2
3 1 2




output
6






Note

In the second sample possible integers are 22, 26, 62 and 66. None of them gives the remainder 1 modulo 2.

In the third sample integers 11, 13, 21, 23, 31 and 33 have remainder 1 modulo 2. There is exactly one way to obtain each of these integers, so the total answer is 6.

题意:

给你n个数,这n个数的大小都在1~9之间,有b块集合,每个集合内都有这n个数,你要从每个集合中取出一个数,并把它们依次拼接起来合并成一个大的整数,问最后这个整数%x得到k的方案数有多少。

题解:

我们可以先把1~9在n出现的次数用occ[i]存下来 ,然后用dp[i][j]表示取前i个数,最终模x后为j的方案数,那么容易得到dp[0][0]=1,dp[i][j]=sum{dp[i-1][a]*occ[d] }(其中(a*10+d)%x==j),但因为b太大,所以我们考虑用矩阵快速幂优化.

由于对于指定的膜数x,我们可以遍历每个余数i和j,再遍历k(k为1-9的数),如果(i*10+k)%x==j,那么矩阵data[i][j]+=occ[k].

然后对构造的这个矩阵进行快速幂运算即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const int inf=0x3fffffff;
const ll mod=1000000007;
const int maxn=100+10;
struct matrix
{
    int n;
    ll data[maxn][maxn];
    matrix(int tn=0){
        n=tn;
        rep(i,0,n) rep(j,0,n) data[i][j]=0;
    }
    void init(){
        rep(i,0,n) data[i][i]=1;
    }
};
matrix Operator *(matrix a,matrix b)
{
    matrix c(a.n);
    int n=a.n;
    rep(i,0,n) rep(j,0,n) rep(k,0,n) c.data[i][j]=(c.data[i][j]+a.data[i][k]*b.data[k][j]%mod)%mod;
    return c;
}
matrix func(matrix a,int b)
{
    matrix t(a.n),ans(a.n);
    ans.init();
    t=a;
    while(b)
    {
        if(b&1) ans=ans*t;
        t=t*t;
        b>>=1;
    }
    return ans;
}
int a[15];
int main()
{
    int n,b,kk,x;
    scanf("%d%d%d%d",&n,&b,&kk,&x);
    rep(i,1,n+1)
    {
        int p;
        scanf("%d",&p);
        a[p]++;
    }
    matrix tmp(x);
    rep(i,0,x)
        rep(j,0,x)
            rep(k,1,10)
            if((i*10+k)%x==j) tmp.data[i][j]+=a[k]; //
    matrix ans(x);
    ans=func(tmp,b);
    cout << ans.data[0][kk] << endl;
    return 0;
}