[SDOI2017]序列计数

序列计数

Alice想要得到一个长度为\(n\)的序列,序列中的数都是不超过\(m\)的正整数,而且这\(n\)个数的和是\(p\)的倍数。

Alice还希望,这\(n\)个数中,至少有一个数是质数。

Alice想知道,有多少个序列满足她的要求。答案对\(20170408\)取模。

\(100\%\)的数据,\(1\leq n \leq 10^9,1\leq m \leq 2\times 10^7,1\leq p\leq 100\)

题解

至少有一个是质数不好做,用所有方案-没有质数的方案。

生成函数就是在\(\mod p\)意义下的统计。然后将它\(n\)次方即可。

用线性筛去掉质数。暴力快速幂+卷积即可。

时间复杂度\(O(m+p^2\log n)\)

#include<bits/stdc++.h>
#define co const
#define il inline
template<class T> T read(){
	T x=0,w=1;char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
	for(;isdigit(c);c=getchar()) x=x*10+c-'0';
	return x*w;
}
template<class T>il T read(T&x){
	return x=read<T>();
}
using namespace std;
typedef long long LL;

co int mod=20170408;
il int add(int a,int b){
	return (a+=b)>=mod?a-mod:a;
}
il int mul(int a,int b){
	return (LL)a*b%mod;
}

co int P=100;
int n,m,p;
int f[P],g[P],ans;

void mul_to(int f[],int g[],int h[]){
	static int a[P],b[P];
	for(int i=0;i<p;++i) a[i]=f[i],b[i]=g[i];
	for(int i=0;i<p;++i) h[i]=0;
	for(int i=0;i<p;++i)
		for(int j=0;j<p;++j)
			h[(i+j)%p]=add(h[(i+j)%p],mul(a[i],b[j]));
}

co int N=20000000+1;
int vis[N],pri[N],pc;
int main(){
	read(n),read(m),read(p);
	for(int i=1;i<=m;++i) ++g[i%p];
	f[0]=1;
	for(int i=n;i;i>>=1,mul_to(g,g,g))
		if(i&1) mul_to(f,g,f);
	ans=f[0];
	vis[1]=1;
	for(int i=2;i<=m;++i){
		if(!vis[i]) pri[++pc]=i;
		for(int j=1;j<=pc&&i*pri[j]<=m;++j){
			vis[i*pri[j]]=1;
			if(i%pri[j]==0) break;
		}
	}
	for(int i=0;i<p;++i) f[i]=g[i]=0;
	for(int i=1;i<=m;++i)if(vis[i]) ++g[i%p];
	f[0]=1;
	for(int i=n;i;i>>=1,mul_to(g,g,g))
		if(i&1) mul_to(f,g,f);
	ans=add(ans,mod-f[0]);
	printf("%d\n",ans);
	return 0;
}

posted on 2019-08-06 20:01  autoint  阅读(178)  评论(0编辑  收藏  举报

导航