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);
}