#【BZOJ4818】序列計數(生成函數) ##題面 BZOJ ##題解 顯然是求一個多項式的若干次方,而且是循環卷積 或者說他是一個$dp$也沒有問題 發現項數不多,直接暴力乘就好了($FFT$可能還慢一些) 而後容斥減掉沒有質數的就好了php
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<map> #include<vector> #include<queue> using namespace std; #define ll long long #define RG register #define MOD 20170408 #define MAX 20000200 inline int read() { int x=0,t=1;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } int n,m,p; int a[100],b[100],c[100]; int ret[100]; void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;} void Multi(int *a,int *b,int *c) { for(int i=0;i<p;++i)ret[i]=0; for(int i=0;i<p;++i) for(int j=0;j<p;++j) add(ret[(i+j)%p],1ll*a[i]*b[j]%MOD); for(int i=0;i<p;++i)c[i]=ret[i]; } void fpow(int *a,int b,int *s) { for(int i=0;i<p;++i)s[i]=0;s[0]=1; while(b){if(b&1)Multi(a,s,s);Multi(a,a,a);b>>=1;} } bool zs[MAX]; int pri[MAX/10],tot=0; int main() { n=read();m=read();p=read(); for(int i=0;i<p;++i)a[i]=m/p; for(int i=1;i<=m%p;++i)a[i]++; fpow(a,n,b); for(int i=0;i<p;++i)a[i]=m/p; for(int i=1;i<=m%p;++i)a[i]++; for(int i=2;i<=m;++i) { if(!zs[i])pri[++tot]=i,a[i%p]--; for(int j=1;j<=tot&&i*pri[j]<=m;++j) { zs[i*pri[j]]=true; if(i%pri[j]==0)break; } } fpow(a,n,c);add(b[0],MOD-c[0]); printf("%d\n",b[0]); return 0; }