Codeforces Round #341 (Div. 2) E. Wet Shark and Blocks

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 chooseexactly one digit from each block and concatenate all of those digits together to form one large integer. For example, if he chooses digit1 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 3ways 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.

Sample test(s)
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 222662 and 66. None of them gives the remainder 1 modulo 2.

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


题意:给你b个block,每个block中的数字都是一样的,每个block有n个数,每个数大于等于1,小于等于9,从每个block中取出一个数,组成一个新数,问这些组成的数中%x==k有多少种不同的情况

思路:如果b比较小,很容易想到dp,dp[i][j]表示用了前i位余数为j的种数,

转态转移方程:dp[i][(j+a)%x]+=dp[i-1][j]*cnt[a];

然而这里的b比较大,那我们便要联想到矩阵快速幂,

我们需要找到一个系数矩阵,m[x][x]进行转化,m[i][j]表示从i转化为j有多少种不同的方式

刚开始的时候,我们的答案是dp[x]={1,0,0,...0,0}

刚开始,我们只有dp[0]是存在的,dp[x]*m[x][x]得到的是一个行矩阵

表示使用了第一个block之后得到每个数的种数,dp[x]*m[x][x]*m[x][x]表示使用了第二个block之后得到每个数的种数

所以使用了n个block之后得到的每个数的种数的情况便是dp[x]*(m[x][x]*m[x][x]*m[x][x]*m[x][x]*...),括号里一共b项

接下来就是要解决系数矩阵m[x][x]的如何得到的问题了,

m[i][(i*10+j)%x]+=cnt[j];  一个数从i变到(i*10+j)%x有多少种方法

所以问题便解决了

#include<bits/stdc++.h>
using namespace std;
const int MOD=1e9+7;
int N;
struct Matrix{
    __int64 m[100][100];
    void init(){
        memset(m,0,sizeof(m));
    }
    Matrix operator *(const Matrix &b) const{
        Matrix ret;
        ret.init();
        for(int i=0;i<N;i++)
            for(int j=0;j<N;j++){
                if(m[i][j]!=0){
                    for(int k=0;k<N;k++)
                     ret.m[i][k]=(ret.m[i][k]+m[i][j]*b.m[j][k])%MOD;
                }
            }
        return ret;
    }
};
Matrix base,ans;
int cnt[10];

Matrix Pow(int n){
    for(int i=0;i<N;i++)
        ans.m[i][i]=1;
    while(n){
        if(n&1)
            ans=ans*base;
        n=n>>1;
        base=base*base;
    }
}

int main(){
    int n,b,k,x,num;
    scanf("%d%d%d%d",&n,&b,&k,&x);
    for(int i=1;i<=n;i++){
        scanf("%d",&num);
        ++cnt[num];
    }
    N=x;
    for(int i=0;i<x;i++)
        for(int j=1;j<10;j++)
            base.m[i][(i*10+j)%x]+=cnt[j];  //一个数从i变到(i*10+j)%x有多少种方法
    Pow(b);
    printf("%d\n",ans.m[0][k]);
    return 0;
}


你可能感兴趣的:(Codeforces Round #341 (Div. 2) E. Wet Shark and Blocks)