bzoj 4818 序列计数 Posted on 2019-12-08 | Views: 生成函数. 用所有的方案数减去每个数都不是质数的方案数. 答案的生成函数显然是一个多项式的 $n$ 次方,并且是循环卷积. 由于长度很小,所以直接暴力卷积就可以了. 时间复杂度 $O(m+p^2\log n)$ . 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091//%std#include<bits/stdc++.h>#define endl '\n'using namespace std;typedef long long ll;inline int read(){ int out=0,fh=1; char jp=getchar(); while ((jp>'9'||jp<'0')&&jp!='-') jp=getchar(); if (jp=='-') fh=-1,jp=getchar(); while (jp>='0'&&jp<='9') out=out*10+jp-'0',jp=getchar(); return out*fh;}const int Mod=20170408;int add(int a,int b){ return (a+b>=Mod)?(a+b-Mod):(a+b);}void inc(int &a,int b){ a=add(a,b);}int mul(int a,int b){ return 1LL * a * b % Mod;}const int M=2e7+10,P=100;int n,m,p;void polymul(int *a,int *b,int *c){ static int tmp[P]; memset(tmp,0,sizeof tmp); for(int i=0;i<p;++i) if(a[i]) for(int j=0;j<p;++j) inc(tmp[(i+j)%p],mul(a[i],b[j])); memcpy(c,tmp,sizeof tmp);}int cnt=0,prime[M/15];bool ism[M];int res[P],a[P];int main(){ n=read(),m=read(),p=read(); int ans=0; for(int i=1;i<=m;++i) ++a[i%p]; int b=n; res[0]=1; while(b) { if(b&1) polymul(res,a,res); polymul(a,a,a); b>>=1; } inc(ans,res[0]); ism[1]=true; for(int i=2;i<=m;++i) { if(!ism[i]) prime[++cnt]=i; int lim=m/i; for(int j=1;j<=cnt && prime[j]<=lim;++j) { ism[i*prime[j]]=true; if(i%prime[j]==0) break; } } memset(a,0,sizeof a); for(int i=1;i<=m;++i) if(ism[i]) ++a[i%p]; b=n; memset(res,0,sizeof res); res[0]=1; while(b) { if(b&1) polymul(res,a,res); polymul(a,a,a); b>>=1; } inc(ans,Mod-res[0]); cout<<ans<<endl; return 0;}