CF621E Wet Shark and Blocks
solution
一个 显然的 \(dp\)
设 \(f_{i, j}\) 表示考虑了前 \(i\) 个格子,当前余数为 \(j\) 的方案数。
转移就枚举当前选的数
\[f_{i + 1, (j * 10 + v) \% x} += f_{i, j}
\]
然后你会发现转移方程的每个 \(f_{i}\) 的转移都是一样的。
所以可以用矩阵加速转移。
初始状态:
\(f_0 = \{1, 0, 0, \dots 0\}\)
对于每个数 \(v\) 修改矩阵:
\(base[j][(j * 10 + v)\% x] += 1\)
最后答案就是 \(base^b \times f[0]\) 的第 \(k\) 行。
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXA = 1e4 + 5;
const int MAXB = 1e5 + 5;
const int MAXC = 1e6 + 5;
const int mod = 1e9 + 7;
int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
return x * f;
}
int n, b, k, x;
struct Matrix{
int a[110][110];
Matrix() {memset(a, 0, sizeof a);}
Matrix operator * (const Matrix &rhs)const{
Matrix ret;
for (int i = 0; i < x; i++)
for (int j = 0; j < x; j++)
for (int k = 0; k < x; k++)
ret.a[i][j] = (ret.a[i][j] + a[i][k] * rhs.a[k][j] % mod) % mod;
return ret;
}
}base, Ans;
Matrix pow(int k) {
Matrix ret;
for (int i = 0; i < x; i++) ret.a[i][i] = 1;
while(k) {
if(k & 1) ret = ret * base;
k >>= 1;
base = base * base;
}
return ret;
}
signed main() {
n = read(), b = read(), k = read(), x = read();
for (int i = 1; i <= n; i++) {
int val = read();
for (int j = 0; j < x; j++)
base.a[j][(j * 10 % x + val % x) % x]++;
}
Ans = pow(b);
cout<<Ans.a[0][k];
return 0;
}