[SMOJ2217]摩天楼

40%：直接 DP

f[i][j]$f[i][j]$ 为前 i$i$ 层组成的数 X$X'$ 使 XmodY=j$X'\mod Y=j$ 的方案数，容易推出状态转移方程：

f[i+1][(10j+Ak)modY]=f[i+1][(10j+Ak)modY]+f[i][j]

//2217.cpp
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>

using namespace std;

const long long Aspe = 1000000007;
const long long MAXN = 5e4 + 100;
const long long MAXY = 100 + 10;

long long N, B, Z, Y;
long long A[MAXN], f[2][MAXY];
pair <long long, long long> C[MAXY];

int main(void) {
freopen("2217.in", "r", stdin);
freopen("2217.out", "w", stdout);
//  scanf("%d%d%d%d", &N, &B, &Z, &Y);
cin >> N >> B >> Z >> Y;
for (long long i = 0; i < N; i++) { cin >> A[i]; /*scanf("%d", &A[i]);*/ ++f[0][A[i] %= Y]; }
sort(A, A + N);
long long cur = 0, cnt = 0, M = 0;
for (long long i = 0; i < N; i++)
if (A[i] == A[cur]) ++cnt; else { C[M++] = make_pair(A[cur], cnt); cur = i; cnt = 1; }
C[M++] = make_pair(A[cur], cnt);
//  f[0][0] = 1;
for (long long i = 0; i + 1 < B; i++)
for (long long j = 0; j < Y; j++)
if (f[i & 1][j]) {
for (long long k = 0; k < M; k++) (f[(i + 1) & 1][(j * 10 + C[k].first) % Y] += f[i & 1][j] * C[k].second % Aspe) %= Aspe;
f[i & 1][j] = 0;
}
//  printf("%d\n", f[(B - 1) & 1][Z]);
cout << f[(B - 1) & 1][Z] << endl;
return 0;
}

100%：

A=[f[i][0]f[i][1]f[i][2]f[i][3]f[i][4]f[i][5]f[i][6]f[i][7]f[i][8]f[i][9]]

C=[f[i+1][0]f[i+1][1]f[i+1][2]f[i+1][3]f[i+1][4]f[i+1][5]f[i+1][6]f[i+1][7]f[i+1][8]f[i+1][9]]

a1,0a2,0...aY2,0aY1,0a1,1a2,1...aY2,1aY1,1...............a1,Y2a2,Y2...aY2,Y2aY1,Y2a1,Y1a2,Y1...aY2,Y1aY1,Y1

A[]$A[]$ 数组为 {3, 5, 6, 7, 8, 9, 5, 1, 1, 1, 1, 5}，则 (0×10+Ai)modY$(0\times10+A_i) \mod Y$ 的取值分布为：1 会出现 4 次，3 会出现 1 次，5 会出现 3 次，6、7、8 和 9 各出现 1 次。也就意味着，C$C$ 的第二列中（f[i+1][1]$f[i+1][1]$）包含着 4 个 f[i][0]$f[i][0]$C$C$ 的第四列中包含着 1 个 f[i][0]$f[i][0]$，依此类推。这样就可以把对应系数填进 D$D$ 的第一行：

[0401031111]

//2217.cpp
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>

using namespace std;

const long long MAXN = 5e4 + 100;
const long long MAXY = 100 + 5;
const long long Ghastlcon = 1000000007;

struct Matrix {
long long val[MAXY][MAXY];
long long row, col;

Matrix () {
for (long long i = 0; i < MAXY; i++)
for (long long j = 0; j < MAXY; j++) val[i][j] = 0;
}

void load_from_array(long long src[][MAXY], long long r, long long c) {
row = r; col = c;
for (long long i = 0; i < r; i++)
for (long long j = 0; j < c; j++) val[i][j] = src[i][j];
}

Matrix operator * (const Matrix x) { //重载运算符
Matrix res; res.row = row; res.col = x.col;
for (int i = 0; i < res.row; i++)
for (int j = 0; j < res.col; j++)
for (int k = 0; k < col; k++)
(res.val[i][j] += val[i][k] * x.val[k][j] % Ghastlcon) %= Ghastlcon;
return res;
}

void debug_output() {
for (long long i = 0; i < row; i++) {
for (long long j = 0; j < col; j++) printf("%I64d ", val[i][j]);
putchar('\n');
}
}
} basic, tmp1, tmp2, ans;

long long N, B, Z, Y;
long long A[MAXN], arr_b[MAXY][MAXY], f[1][MAXY];

Matrix matrix_pow(Matrix cur, long long k) { //矩阵快速幂
if (k == 1) return cur;
Matrix tmp = matrix_pow(cur, k >> 1);
if (k & 1) return tmp * tmp * cur; else return tmp * tmp;
}

int main(void) {
freopen("2217.in", "r", stdin);
freopen("2217.out", "w", stdout);
scanf("%I64d%I64d%I64d%I64d", &N, &B, &Z, &Y);
for (long long i = 0; i < N; i++) { scanf("%I64d", &A[i]); ++f[0][A[i] % Y]; }
if (B == 1) { printf("%I64d\n", f[0][Z]); return 0; } //边界
for (long long i = 0; i < Y; i++)
for (long long j = 0; j < N; j++)
++arr_b[i][(i * 10 + A[j]) % Y]; //推出基础矩阵
}