【38.24%】【codeforces 621E】 Wet Shark and Blocks

来源:互联网 发布:电影售票软件 编辑:程序博客网 时间:2024/05/16 01:35

time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard 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, n, b, k 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.

【题解】

有b个盒子;
每个盒子里都有n个数字;
让你从每个盒子中都取出一个数字1..9;
顺序组成长度为b的数字;
问数字取余结果为k的数字个数;
预处理出每个数字有多少个;
如果b没那么大的话可以这样写;
设dp[i][j]表示前i个数字组成的数取余结果为j的方案数
dp[i+1][(j*10+t)%k]+=dp[i][j]*num[t];
对于每一个转移;
其实都是(j*10+t)%k += t这个数字的个数*dp[i][j];
即每个转移都是一样的;
则一开始预处理出一个初始矩阵a[i][j];
这个矩阵表示的是
一开始余数为i的时候利用1-9这几个数字到余数为j的方案数增加量;
(还记得图论的从某个点到另外一个点恰好走k步的方案吗;http://blog.csdn.net/harlow_cheng/article/details/52615106我们一开始的初始矩阵也是任意两个点之间能否到达->即从i点到j点的方案增加量,(我们一开始是设为1表示联通的,那不正是方案增加量吗?)),这里也可以看成是知道任意两点之间(0..x-1)->(0..x-1)的连通关系,但是初始的时候任意两点联通对方案的增加量变成了一个可能大于1的数字);
求矩阵的b次幂;
最后的那个矩阵是为了加深理解;可以不用乘;->矩阵E->从0->0一开始的方案都为1,即都不变;
乘一下就能够和答案联系在一起了;
即从一开始取余为0->…->k
最后输出ans[0][k];

#include <cstdio>#include <cmath>#include <set>#include <map>#include <iostream>#include <algorithm>#include <cstring>#include <queue>#include <vector>#include <stack>#include <string>#define lson L,m,rt<<1#define rson m+1,R,rt<<1|1#define LL long longusing namespace std;const int MAXMOD = 120;const LL MOD = 1e9+7;const int dx[5] = {0,1,-1,0,0};const int dy[5] = {0,0,0,-1,1};const double pi = acos(-1.0);struct abc{    LL jz[MAXMOD][MAXMOD];};LL num[10];int n,b,k,x;LL f[MAXMOD];abc a;void input_LL(LL &r){    r = 0;    char t = getchar();    while (!isdigit(t)) t = getchar();    LL sign = 1;    if (t == '-')sign = -1;    while (!isdigit(t)) t = getchar();    while (isdigit(t)) r = r * 10 + t - '0', t = getchar();    r = r*sign;}void input_int(int &r){    r = 0;    char t = getchar();    while (!isdigit(t)) t = getchar();    int sign = 1;    if (t == '-')sign = -1;    while (!isdigit(t)) t = getchar();    while (isdigit(t)) r = r * 10 + t - '0', t = getchar();    r = r*sign;}abc jc(abc a, abc b){    abc c;    for (int i = 0; i <= x-1; i++)        for (int j = 0; j <= x-1; j++)        {            c.jz[i][j] = 0;            for (int k = 0; k <= x-1; k++)                c.jz[i][j] = (c.jz[i][j] + a.jz[i][k] * b.jz[k][j])%MOD;        }    return c;}abc ksm(int x){    if (x == 1)        return a;    abc temp;    temp = ksm(x>>1);    temp = jc(temp,temp);    if (x&1)        temp = jc(temp,a);    return temp;}int main(){    //freopen("F:\\rush.txt", "r", stdin);    input_int(n);input_int(b);input_int(k);input_int(x);    for (int i = 1;i <= n;i++)    {        int temp;        input_int(temp);        num[temp]++;    }    int now = 0;    for (int i = 0;i<=x-1;i++)        for (int j = 1;j <= 9;j++)            a.jz[i][(i*10+j)%x]=(a.jz[i][(i*10+j)%x] + num[j])%MOD;    abc ans = ksm(b);    abc E;    E.jz[0][0] = 1;    ans = jc(E,ans);    printf("%I64d\n",ans.jz[0][k]);    return 0;}
0 0