競プロ典型 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;
}	
posted @ 2021-12-08 17:11  fhq_treap  阅读(171)  评论(1编辑  收藏  举报