BZOJ3160【万径人踪灭】 【FFT】

时间:2021-11-26 22:34:08

。。恩 打了四五遍 不会也背出来了。。

BZOJ3160 【听说时限紧?转C++的优势么?】

上AC代码 fft

 /*Problem: 3160
User: cyz666
Language: C++
Result: Accepted
Time:1992 ms
Memory:18492 kb
****************************************************************/ #include <bits/stdc++.h>
#define LL long long
const LL mo=;
const double pi=acos(-1.0);
using namespace std;
struct cp{
double x,y;
cp(double a=,double b=):x(a),y(b){}
//cp(double a=0,double b=0){x=a,y=b;}
}a[],b[],W[];
int h[],rev[],f[],c[],n,x,m;
char s; LL ans;
cp operator +(cp a,cp b){
cp c(a.x+b.x,a.y+b.y);
return c;
}
cp operator *(cp a,cp b){
cp c(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
return c;
}
cp operator -(cp a,cp b){
return (cp){a.x-b.x,a.y-b.y};
}
void fft(cp a[],int n,int d=){
if (d<) reverse(a+,a+n);
for (int i=;i<n;++i)
if (i<rev[i]) swap(a[i],a[rev[i]]);
for (int i=;i<n/;++i)
W[i]=cp(cos(*pi/n*i),sin(*pi/n*i));
for (int m=,k=;m<=n;k=m,m<<=)
for (int i=;i<n;i+=m)
for (int j=i;j<i+k;++j){
cp u=a[j],v=a[j+k]*W[n/m*(j-i)];
a[j]=u+v,a[j+k]=u-v;
}
if (d<) for (int i=;i<n;++i) a[i].x/=n;
}
int main(){
while (scanf("%c",&s)&&isalpha(s))
s=='a'?c[++++n]=:c[++++n]=;
c[]=-; c[n+]=-;
for (int i=;i<=n;++i){
if (x+f[x]>i) f[i]=min(f[x+x-i],x+f[x]-i);
while (c[i+f[i]]==c[i-f[i]]) ++f[i]; --f[i];
if (i+f[i]>x+f[x]) x=i;
ans+=f[i]/; if (ans>=mo) ans-=mo;
}
m=ceil((log(n)/log())); m=<<m;
for (int i=;i<m;++i)rev[i]=(rev[i>>]>>)+(m>>)*(i&);
x=; for (int i=;i<=n;++++i) c[++x]=c[i]; n=x;
for (int i=;i<=n;++i) c[i]==?a[i].x=:b[i].x=;
fft(a,m); fft(b,m);
for (int i=;i<m;++i) a[i]=a[i]*a[i],b[i]=b[i]*b[i];
fft(a,m,-); fft(b,m,-);
h[]=; for (int i=;i<=n;++i)h[i]=(h[i-]+h[i-])%mo;
int x; ans=mo-ans;
for (int i=;i<n+n;++i){
x=round(a[i].x+b[i].x);
ans+=h[x+>>]-; if (ans>=mo) ans-=mo;
}
ans=(ans-n++mo)%mo;
printf("%lld",ans);
return ;
}

KriTo

然后 顺手写了个ntt板子扔这(没用题目测过对不对)

mo的原根g的定义:g^1,g^2,...,g^(mo-1) 在%mo意义下各不相同。

 #include <bits/stdc++.h>
#define LL long long
using namespace std;
int g1,g2,N,n,k,x,W[],a[],b[],rev[],mo1,mo2;
LL po(LL x,LL y,LL mo){
LL z=; if (y<) y=y%(mo-)+mo-;
for (;y;y>>=,x=x*x%mo)
if (y&) z=z*x%mo;
return z;
}
int getg(LL mo){
LL y=mo-,x=floor(sqrt(y)); int fl;
for (int g=;;++g){
fl=;
for (int i=;i<=x;++i) if (!(y%i))
if (po(g,i,mo)==||po(g,y/i,mo)==) {fl=;break;}
if (fl) return g;
}
}
void ntt(int a[],int n,int d,int mo,int G){ //n整除(mo-1)
if (d<) reverse(a+,a+n);
for (int i=;i<n;++i)
if (i<rev[i]) swap(a[i],a[rev[i]]);
W[]=; LL X=po(G,(mo-)/n,mo);
for (int i=;i<n/;++i) W[i]=X*W[i-]%mo;
for (int m=,k=;m<=n;k=m,m<<=)
for (int i=;i<n;i+=m)
for (int j=i;j<i+k;++j){
int u=a[j],v=1ll*a[j+k]*W[n/m*(j-i)]%mo;
a[j]=u+v>=mo?u+v-mo:u+v;
a[j+k]=u-v<?u-v+mo:u-v;
}
if (d<){
X=po(n,mo-,mo);
for (int i=;i<n;++i) a[i]=X*a[i]%mo;
}
}
int main(){
mo1=; mo2=;
g1=getg(mo1); g2=getg(mo2);
scanf("%d%d",&n,&k); W[]=;
for (int i=;i<=n;++i)
scanf("%d",&x),a[x]=,b[x]=;
N=;
for (int i=;i<N;++i) rev[i]=rev[i>>]>>|(i&?N>>:);
ntt(a,N,,mo1,g1); ntt(b,N,,mo2,g2);
for (int i=;i<N;++i)
a[i]=po(a[i],k,mo1),b[i]=po(b[i],k,mo2);
ntt(a,N,-,mo1,g1); ntt(b,N,-,mo2,g2);
for (int i=;i<N;++i){
if (a[i]<) a[i]+=mo1;
if (b[i]<) b[i]+=mo2;
}
for (int i=;i<N;++i) if (a[i]||b[i]) printf("%d ",i); puts("");
return ;
}

AsuNa

若多项式相乘的最高次为n, 则FFT,NTT的数组大小要开到>n的最小的2的幂。 即 1<<(int)ceil(log(n+1)/log(2))

给几个模数:

1004535809=479*2^21+1,   原根=3

998244353=7*17*2^23+1 ,原根=3

469762049=7*2^26+1      ,原根=3