您的位置:首页 > 其它

codeforces 621E(dp, matrices)

2016-02-01 14:50 351 查看
题目大意:

输入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]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: