codeforces 621E(dp, matrices)

来源:互联网 发布:linux echo命令详解 编辑:程序博客网 时间:2024/06/08 11:37

题目大意:

  输入4个数字, n, b, k, x;  

   有b数量的的 “包裹”,  每个”包裹“中含有相同的n个数字, 数字a的取值为  0 < a  < 10;  从b数量的”包裹“中取出这些数字组成一个数字num; 比如 有 3个”包裹“, 从左到右依次取出1, 2, 3;  则组成一个3位数 123;  现在让你求有多少个方案满足num % x== k ;  因为方案数可能很多,最后的结果取余1e9+7;

  

题目分析:

First, let us build an X by X matrix. We will be applying matrix exponentiation on this matrix. For each modulo value T from 0 to X — 1, and each value in the array with index i between 1 and n, we will do: matrix[T][(10 * T + arr[i]) % X]++. This is because, notice that for each block we allow one more way to go between a modulo value T, and (10 * T + arr[i]) % X. We are multiplying T by 10 because we are "left-shifting" the number in a way (i.e. changing 123 -> 1230), and then adding arr[i] to it. Notice that this basically simulates the concatenation that Wet Shark is conducting, without need of a brute force dp approach.

这是官方题解,我大致翻译一下: 

  建立一个x * x的矩阵 matrix, 我们将使用矩求幂的方法完成(矩阵快速幂), 对于每一个取余x后的值T,取值范围( 0 < T < x-1 ), 然后对于我们输入的数字(block中的n个值),我们将进行: matrix[T][(10*T+arr[i])%x]++; 这样做的原因是, 表示从T 到达 (10*T+arr[i])%x 的方案数, 建议参考代码;  (10*T+arr[i])%x 是模拟两个数字的结合(因为题目要求取余结果,根据取余原则,%x即可);


#include <bits/stdc++.h>using namespace std;const int mod = 1e9+7;const int maxn = 100+5;int matrix[maxn][maxn], s[maxn][maxn];int n, b, k, x;int cnt[10], tmp[maxn][maxn];void mul(int a[][maxn], int b[][maxn]){    for(int i = 0; i < x; ++i){        for(int j = 0; j < x; ++j){            int t(0);            for(int k = 0; k < x; ++k){                t = (t+1LL*a[i][k]*b[k][j])%mod;            }            tmp[i][j] = t;        }    }    for(int i = 0; i < x; ++i)        for(int j = 0; j < x; ++j)            a[i][j] = tmp[i][j];}int main(){    while(~scanf("%d%d%d%d", &n, &b, &k, &x)){        for(int i = 0; i < n; ++i){            int x;            scanf("%d", &x);            cnt[x]++;        }        for(int i = 0; i < x; ++i)            for(int j = 0; j < 10; ++j){                matrix[i][(i*10+j)%x] += cnt[j];            }        for(int i = 0; i < x; ++i) s[i][i] = 1;        while(b){            if(b&1)                mul(s, matrix);            mul(matrix, matrix);            b /= 2;        }        printf("%d\n", s[0][k]);    }}

 

0 0
原创粉丝点击