正题
这题就是裸的单位根反演,会做的就会做,不会的就怎么样也做不出来,可以看看我的Blog或者看看其他巨神的Blog再来做这题。
#include<bits/stdc++.h>
using namespace std;
const int K=1<<20;
int n,p,k,limit,l=0;
int where[K<<1];
long long w[K];
long long f[K<<1],g[K<<1];
const long long mod=998244353;
long long ksm(long long x,long long t){
long long tot=1;
while(t){
if(t&1) (tot*=x)%=mod;
(x*=x)%=mod;
t/=2;
}
return tot;
}
long long C(long long x){
if(x==1 || x==0) return 0;
return x*(x-1)/2%k;
}
void DFT(long long *now,int idft){
for(int i=0;i<limit;i++) if(i<where[i]) swap(now[i],now[where[i]]);
long long wn,w,a,b;
for(int l=2;l<=limit;l<<=1){
wn=ksm(3,(mod-1)/l*idft%(mod-1));
for(int i=0;i<limit;i+=l){
w=1;
for(int x=i,y=i+l/2;y<i+l;x++,y++,(w*=wn)%=mod){
a=now[x],b=now[y]*w%mod;
now[x]=a+b,now[x]>=mod?now[x]-=mod:0;
now[y]=a-b,now[y]<0?now[y]+=mod:0;
}
}
}
}
int main(){
scanf("%d %d %d",&n,&p,&k);
w[0]=1;w[1]=ksm(3,(mod-1)/k);
for(int i=2;i<k;i++) w[i]=w[i-1]*w[1]%mod;
for(int i=0;i<k;i++) f[i]=i*w[C(i)]%mod;
for(int i=0;i<k;i++) g[i]=w[C(i)]*ksm((p*w[i]+1)%mod,n)%mod;
limit=1,l=0;
while(limit<2*k-1) limit*=2,l++;
for(int i=0;i<limit;i++) where[i]=(where[i>>1]>>1) | ((i&1)<<(l-1));
DFT(f,1);DFT(g,1);
for(int i=0;i<limit;i++) f[i]=f[i]*g[i]%mod;
DFT(f,mod-2);
long long tmp=ksm(limit,mod-2);
for(int i=0;i<limit;i++) f[i]=f[i]*tmp%mod;
long long ans=0;
for(int i=0;i<limit;i++) f[i]=f[i]*ksm(w[C(i)],mod-2)%mod,ans+=f[i];
printf("%lld",(1ll*n*p%mod*ksm(p+1,n-1)%mod-ans%mod*ksm(k,mod-2)%mod+mod)*ksm(k,mod-2)%mod);
}
本文深入探讨了单位根反演在算法竞赛中的应用,通过具体实例讲解了如何利用单位根反演解决复杂问题。文章提供了详细的代码实现,包括DFT(离散傅里叶变换)和单位根的快速幂计算,以及组合数的计算技巧。
859

被折叠的 条评论
为什么被折叠?



