競プロ典型 90 問泛做
被叉姐推荐了競プロ典型 90 問。
★7
005 - Restricted Digits(★7)
可以容易思考出矩阵乘法的做法\(O(B^3logn)\)
但其实我们发现其实质为多项式乘法,考虑进位后我们仍旧可以用\(B^2\)处理两个答案合并。
那么可以直接分治即可。
005 - Restricted Digits(★7)
#include<iostream>
#include<cstdio>
#define ll long long
#define N 200005
#define P ((ll)1e9 + 7)
ll n,B,K,pw[64],pre[64][1005],f[64][1005];
int a[N];
int main(){
scanf("%lld%lld%lld",&n,&B,&K);
for(int i = 1;i <= K;++i)
scanf("%d",&a[i]),a[i] %= B;
pw[0] = 10;
for(int i = 1;i <= 61;++i)
pw[i] = pw[i - 1] * pw[i - 1] % B;
for(int i = 1;i <= K;++i)
pre[0][a[i]] ++ ;
for(int i = 0;i <= 61;++i)
for(int j = 0;j < B;++j)
for(int k = 0;k < B;++k){
int to = (j * pw[i] + k) % B;
pre[i + 1][to] = pre[i + 1][to] + pre[i][j] * pre[i][k];
pre[i + 1][to] %= P;
}
f[0][0] = 1;
for(int i = 0;i <= 61;++i){
if(n & (1ll << i))
for(int j = 0;j < B;++j)
for(int k = 0;k < B;++k){
int to = (j * pw[i] + k) % B;
f[i + 1][to] = f[i + 1][to] + pre[i][j] * f[i][k];
f[i + 1][to] %= P;
}
else
for(int j = 0;j < B;++j)
f[i + 1][j] = f[i][j];
}
std::cout<<f[62][0]<<std::endl;
}