BSOJ3972题解

这玩意儿看着就很 GF。用 \(x\) 来枚举和 \(y\) 来钦定模 \(p\) 的余数可以得到:

\[\prod_{i=0}^{n-1}(\sum_{k=0}^{9}x^ky^{k10^i})\bmod{y^p-1} \]

答案是取其 \([x^iy^0]\) 然后做个前缀和。下面考虑 \(10^i\bmod p\)

\[\prod_{i=0}^{p-1}(\sum_{k=0}^{9}x^ky^{ki})^{\sum_{j=0}^{n-1}[10^j\bmod p=i]}\bmod{y^p-1} \]

指数上面那个东西可以看成是 \(\sum_{i=0}^{n-1}x^{10^i}\bmod{x^{p}-1}\) 然后用倍增什么的 \(p^2\log n\) 随便搞搞,也可以找循环节然后 \(O(p)\)

\[\prod_{i=0}^{p-1}(\sum_{k=0}^{9}x^ky^{ki})^{f_i}\bmod{y^p-1} \]

\[\prod_{i=0}^{p-1}(\sum_{k=0}^{9}(xy^i)^k)^{f_i}\bmod{y^p-1} \]

考虑令 \(z=y^i\),那么对于一个 \(\sum\) 可以改变其做法为:

\[F_i(x,y)=(\sum_{k=0}^{9}(xz)^k)^{f_i}\bmod{z^p-1}\bmod{x^{m+1}} \]

容易发现 \(x\)\(z\) 是绑定在一起的,也就是说最终的 GF 只有 \(m+1\) 项而不是 \(O(pm)\) 项。

问题变为求 \((\frac{1-x^{10}}{1-x})^{f_i}\bmod{x^{m+1}}\),这玩意儿显然可以随便组合数一下再卷一下,复杂度 \(O(m^2)\)

接下来需要计算的是:

\[F(x,y)=\prod_{i=0}^{p-1}(\frac{1-(xy^i)^{10}}{1-xy^i})^{f_i}\bmod{y^p-1}\bmod{x^{m+1}-1} \]

\[\prod_{i=0}^{p-1}\frac{1}{(1-xy^i)^{f_i}}\prod_{i=0}^{p-1}(1-(xy^i)^{10})^{f_i}\mod{y^p-1} \]

这时候我们对后面的部分做背包可以做到 \(O(\frac{p^2m^2}{10^2})\) 的复杂度,前面的可以做到 \(O(p^2m^2)\),可以通过。

跑得比想象的快很多啊?

#include<cstdio>
const int M=1005,mod=998244353;
int n,p,m,X,Y,C[M],F[M],inv[M];int ans[M][55],tmp[M][55];int id[55],sum[55];bool vis[M];
struct Barrett{
	int B,m;
	Barrett(const int&m=2):m(m),B((1<<16)/m){}
	friend inline int operator%(const int&a,const Barrett&mod){
		int r=a-(mod.B*a>>16)*mod.m;return r>=mod.m?r-mod.m:r;
	}
}P;
inline int pow(int a,int b=mod-2){
	int ans(1);for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)ans=1ll*ans*a%mod;return ans;
}
inline void init(const int&n){
	inv[0]=inv[1]=1;for(int i=2;i^n;++i)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
}
inline void GetF(const int&a,const int&k){
	if(!k)return;
	for(int C(1),i=0;i*10<m&&i<=k;++i){
		if(i)C=1ll*(k-i+1)*inv[i]%mod*C%mod;
		const int&c=i&1?mod-C:C;
		for(int x=0;x<X-i;++x)for(int y=0;y<Y;++y){
			const int&tx=x+i,ty=(y+a*i*10)%P;tmp[tx][ty]=(tmp[tx][ty]+1ll*c*ans[x][y])%mod;
		}
	}
	for(int x=0;x^X;++x)for(int y=0;y^Y;++y)ans[x][y]=tmp[x][y],tmp[x][y]=0;
}
inline void GetG(const int&a,const int&k){
	if(!k)return;
	for(int C(1),i=0;i<m;++i){
		if(i)C=1ll*(k+i-1)*inv[i]%mod*C%mod;
		const int&c=C;
		for(int x=0;x<X-i;++x)for(int y=0;y<Y;++y){
			const int&tx=x+i,ty=(y+a*i)%P;tmp[tx][ty]=(tmp[tx][ty]+1ll*c*ans[x][y])%mod;
		}
	}
	for(int x=0;x^X;++x)for(int y=0;y^Y;++y)ans[x][y]=tmp[x][y],tmp[x][y]=0;
}
signed main(){
	int len;ans[0][0]=1;
	scanf("%d%d%d",&n,&p,&m);++m;init(m);X=(m-1)/10+1;Y=p;P=Barrett(p);
	for(int x=1,cnt=1;;x=10*x%P,++cnt){
		if(id[x]){
			len=cnt-id[x];
			for(int t=x;;){
				vis[t]=true;t=10*t%P;if(t==x)break;
			}
			break;
		}
		id[x]=cnt;
	}
	for(int i=0;i^p;++i)GetF(i,(id[i]&&n>=id[i]?(vis[i]?(n-id[i])/len:0)+1:0));
	for(int x=0;x^X;++x)for(int y=0;y^Y;++y)tmp[x*10][y]=ans[x][y];X=m;Y=p;
	for(int x=0;x^X;++x)for(int y=0;y^Y;++y)ans[x][y]=tmp[x][y],tmp[x][y]=0;
	for(int i=0;i^p;++i)GetG(i,(id[i]&&n>=id[i]?(vis[i]?(n-id[i])/len:0)+1:0));
	for(int sum(0),i=0;i^m;++i)sum=(sum+ans[i][0])%mod,printf("%d ",sum);
}
posted @ 2022-06-24 14:39  Prean  阅读(26)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};