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

该博客讨论了一道编程题目,涉及到在给定的数字块中选择数字并组合成一个大整数,然后求该整数模x等于k的方案数。通过矩阵快速幂的方法优化动态规划解决方案,解决大数据量的问题。
摘要由CSDN通过智能技术生成


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 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.


题意:

给你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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值