题解:P12771 [POI 2018 R3] 多项式 Polynomial
Associate_Entropy · · 题解
给定一个
分析
第一眼看到题目,首先想到任意模数的 Chirp Z-Transform,但是发现模数太任意了,可以很小,导致组合数没有逆元,遂放弃。
接着我们考虑能否利用
pw[0]=1;
for(int i=1;i<=n;i++)pw[i]=1ll*pw[i-1]*q%m;
for(d=1;d<=n;d<<=1)if(pw[d]==1)break;
for(int i=0;i<n;i+=d){
work(a+i);
for(int j=1;j<=d;j++)add(ans[j],1ll*val[j]*kpow(pw[j],i)%m);
}
int ss=0;
for(int i=1;i<=d;i++)add(ss,1ll*ans[i]*(n/d)%m);
printf("%d\n",ss);
for(int i=0;i<n;i+=d)
for(int j=1;j<=d;j++)printf("%d ",ans[j]);
问题可以转化为求
我们回想一下普通 fft 在干什么事情。要想快速实现系数向点值的转化,我们将当前多项式按奇偶项分开,如
单位根就有这样的优势,
但是,
不过这样就做不了了吗? 答案是否定的。因为我们意识到,在
于是这题就顺利地做完了。
Code
变量名和写法有所调整。
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0;char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
return x;
}
const int N=1<<22;
int n,m,c,mod,g,a[N],pw[N],rev[N],ans[N];
void add(int &x,int y){x+=y;if(x>=mod)x-=mod;}
int kpow(int t1,int t2){
int res=1;
while(t2){
if(t2&1)res=1ll*res*t1%mod;
t1=1ll*t1*t1%mod;t2>>=1;
}
return res;
}
void ntt(int *f){
int lg=__lg(n);
for(int i=1;i<n;i++){
rev[i]=(rev[i>>1]>>1)|((i&1)<<lg-1);
if(i<rev[i])swap(f[i],f[rev[i]]);
}
for(int x=1,y=2;y<=n;x<<=1,y<<=1){
int z=pw[n/y];//求y次单位根
for(int i=0;i<n;i+=y)
for(int w=1,j=i;j<i+x;j++,w=1ll*w*z%mod){
int p=f[j],q=1ll*w*f[j+x]%mod;
f[j]=p+q<mod? p+q:p+q-mod;
add(f[j+x]=1ll*pw[n>>1]*q%mod,p);
}
}
}
int main(){
m=read();mod=read();c=read();
pw[0]=1;
for(int i=1;i<=m;i++)pw[i]=1ll*pw[i-1]*c%mod;
for(n=1;n<=m;n<<=1)if(pw[n]==1)break;
for(int i=0;i<m;i++)a[i]=read()%mod;
for(int i=0;i<m;i+=n){
ntt(a+i);
for(int j=0;j<n;j++)add(ans[j],1ll*a[j+i]*kpow(pw[j],i)%mod);
}
int ss=0;
for(int i=0;i<n;i++)add(ss,1ll*ans[i]*(m/n)%mod);
printf("%d\n",ss);
for(int i=0;i<m;i+=n){
for(int j=1;j<n;j++)printf("%d ",ans[j]);
printf("%d ",ans[0]);
}
}