LGP3702题解

很容易想到容斥,计算不包含质数的方案数和总方案数。

\(f[n][i]\) 表示长度为 \(n\) 的序列,每个元素的和对 \(p\) 取模的结果。

容易有 \(f[n][i]=\sum_{j=0}^pf[n-1][i-j\bmod p]\times g[j]\)\(g[j]\) 代表选出的数(非质数或 \([1,m]\) 的整数)对 \(p\) 取模为 \(j\) 的数的数量。

容易发现这是一个循环卷积,容易做到 \(O(p^2\log n)\)

我们知道 \(DFT\) 做的也是循环卷积,所以我们把 \(w_n^{0\sim n-1}\) 拉出来,将 \(g\) 看做多项式,带入这些点值后快速幂,最后 \(IDFT\) 可以做到 \(O(p^2+p\log n)\)

但是 \(20170408\) 不是质数 是省选的日期,进行质因数分解后可能系数没有下标,所以写了个 \(O(p^2\log n)\) 就溜了(

#include<cstdio>
typedef unsigned ui;
const ui M=105,N=2e7+5,mod=20170408;
ui n,m,p,g[M];bool zhi[N];
inline void times(ui*f,ui*g){
	static ui sav[M<<1];
	for(ui i=0;i<p;++i)for(ui j=0;j<p;++j)sav[i+j]=(sav[i+j]+1ull*f[i]*g[j])%mod;
	for(ui i=0;i<p;++i)f[i]=(sav[i]+sav[i+p])%mod,sav[i]=sav[i+p]=0;
}
inline void sieve(const ui&M){
	for(ui i=2;i*i<=M;++i)if(!zhi[i])for(ui j=i*i;j<=M;j+=i)zhi[j]=true;zhi[1]=true;
}
inline ui pow(ui*g,ui n){
	static ui f[M];
	for(ui i=0;i<p;++i)f[i]=0;f[0]=1;
	for(;n;n>>=1,times(g,g))if(n&1)times(f,g);
	return f[0];
}
signed main(){
	ui sum1,sum2;
	scanf("%u%u%u",&n,&m,&p);sieve(m);
	const ui&x=m%p,&y=m/p;
	for(ui i=0;i<p;++i)g[i]=1<=i&&i<=x?y+1:y;
	sum1=pow(g,n);
	for(ui i=0;i<p;++i)g[i]=0;
	for(ui j=1,i=1;i<=m;++i){
		if(zhi[i])++g[j];if(++j==p)j=0;
	}
	sum2=pow(g,n);
	printf("%u",(mod+sum1-sum2)%mod);
}
posted @ 2022-02-28 10:37  Prean  阅读(30)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};