2022.03.01 FFT与NNT

https://www.luogu.com.cn/blog/wangrx/solution-p1919

https://www.luogu.com.cn/blog/attack/solution-p38032

P3803 【模板】多项式乘法(FFT)(NTT模板)

https://www.luogu.com.cn/problem/P3803

#include<bits/stdc++.h>
using namespace std;

#define int long long
const int N=3e6+10;
const int mod=998244353;
const int G=3;
const int Gi=332748118;
int n,m,limit=1,len,rev[N],a[N],b[N];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline int powi(int x,int y){
	int fin=1;
	while(y){
		if(y&1)fin=fin*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return fin;
}
inline void NTT(int *A,int flag){
	for(int i=0;i<limit;i++)if(i<rev[i])swap(A[i],A[rev[i]]);
	for(int mid=1;mid<limit;mid<<=1){
		int Wn=powi(flag==1?G:Gi,(mod-1)/(mid<<1));
		for(int j=0;j<limit;j+=(mid<<1)){
			int W=1;
			for(int k=0;k<mid;k++,W=W*Wn%mod){
				int x=A[j+k],y=W*A[j+k+mid]%mod;
				A[j+k]=(x+y)%mod;
				A[j+k+mid]=(x+mod-y)%mod;
			}
		}
	}
}

signed main(){
	n=read();m=read();
	for(int i=0;i<=n;i++)a[i]=read(),a[i]=(a[i]+mod)%mod;
	for(int i=0;i<=m;i++)b[i]=read(),b[i]=(b[i]+mod)%mod;
	while(limit<=n+m)limit<<=1,++len;
	for(int i=0;i<limit;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(len-1));
	NTT(a,1);NTT(b,1);
	for(int i=0;i<limit;i++)a[i]=a[i]*b[i]%mod;
	NTT(a,-1);
	int inv=powi(limit,mod-2);
	for(int i=0;i<=n+m;i++)cout<<a[i]*inv%mod<<" ";
	return 0;
}

P1919 【模板】A*B Problem 升级版(FFT 快速傅里叶变换(注意:可能结果的第一个系数也要进一……)(NTT模板1.1)

https://www.luogu.com.cn/problem/P1919

这里对于NTT模板进行了优化:

  1. 不用每次计算powi(flag==1?3:inv3,(mod-1)/(mid<<1))了,直接搞了两个数组,一个叫powi3就是存3的次方的,一个叫powinv3就是存3的次方的逆元的
  2. 没了/斜眼笑
#include<bits/stdc++.h>
using namespace std;

#define int long long
const int N=4e6+10;
const int mod=998244353;
int n,a[N],b[N],c[N],rev[N],lena,lenb;
int pow3[N],powinv3[N],inv3,inv,limit=1,len;
char s[N];

inline int powi(int x,int y){
	int fin=1;
	while(y){
		if(y&1)fin=fin*x%mod;
		x=x*x%mod;y>>=1;
	}
	return fin;
}
inline void NTT(int *A,int flag){
	for(int i=0;i<limit;i++)if(i<rev[i])swap(A[i],A[rev[i]]);
	for(int mid=1;mid<limit;mid<<=1){
		int Wn=(flag==1?pow3[mid<<1]:powinv3[mid<<1]);
		//int Wn=powi(flag==1?3:inv3,(mod-1)/(mid<<1));
		for(int j=0;j<limit;j+=(mid<<1)){
			int W=1;
			for(int k=0;k<mid;k++,W=(W*Wn)%mod){
				int x=A[k+j],y=A[k+j+mid]*W%mod;
				A[j+k]=(x+y)%mod;
				A[j+k+mid]=(x-y+mod)%mod;
			}
		}
	}
}

signed main(){
	inv3=powi(3,mod-2);
	//cout<<inv3<<endl;
	scanf("%s",s);//printf("%s\n",s);
	lena=strlen(s);
	for(int i=0;i<lena;i++)a[i]=s[i]-'0';//,cout<<a[i]<<" ";cout<<endl;
	scanf("%s",s);//printf("%s\n",s);
	lenb=strlen(s);
	for(int i=0;i<lenb;i++)b[i]=s[i]-'0';//,cout<<b[i]<<" ";cout<<endl;
	--lena;--lenb;
	while(limit<=lena+lenb)limit<<=1,++len;
	for(int i=0;i<limit;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(len-1));
	for(int i=1;i<=limit;i<<=1)
	pow3[i]=powi(3,(mod-1)/i),powinv3[i]=powi(inv3,(mod-1)/i);
	NTT(a,1);NTT(b,1);
	for(int i=0;i<limit;i++)a[i]=a[i]*b[i]%mod;
	NTT(a,-1);
	inv=powi(limit,mod-2);
	for(int i=0;i<=lena+lenb;i++)a[i]=a[i]*inv%mod;//,cout<<a[i]<<" ";cout<<endl;
	for(int i=0;i<=lena+lenb;i++)c[i]=a[lena+lenb-i];//,cout<<c[i]<<" ";cout<<endl;
	for(int i=0;i<=lena+lenb+2;i++)if(c[i]>=10)c[i+1]+=c[i]/10,c[i]%=10;
	n=lena+lenb+4;
	while(c[n]==0)--n;
	for(int i=n;i>=0;i--)cout<<c[i];
	return 0;
}

P2553 [AHOI2001]多项式乘法

https://www.luogu.com.cn/problem/P2553

这是道美丽的字符串,但是eleveni挂在NTT上

#include<bits/stdc++.h>
using namespace std;

#define int long long
const int N=666;
const int mod=998244353;
int limit=1,a[N],b[N],rev[N],len,inv,inv3,powi3[N],powinv3[N];
struct node{
	int x,y;
	bool operator <(const node &b)const{
		return y<b.y;
	}
}s[N];
string t;

inline int powi(int x,int y){
	int fin=1;
	while(y){
		if(y&1)fin=fin*x%mod;
		x=x*x%mod;y>>=1;
	}
	return fin;
}
inline void NTT(int *A,int flag){
	for(int i=0;i<limit;i++)if(i<rev[i])swap(A[i],A[rev[i]]);
	//cout<<"Case mid "<<endl;
	for(int mid=1;mid<limit;mid<<=1){
		//int Wn=flag==1?powi3[mid<<1]:powinv3[mid<<1];
		int Wn=powi(flag==1?3:inv3,(mod-1)/(mid<<1));
		for(int j=0;j<limit;j+=(mid<<1)){
			int W=1;
			for(int k=0;k<mid;k++,W=W*Wn%mod){
				int x=A[j+k],y=A[j+k+mid]*W%mod;
				A[j+k]=(x+y)%mod;
				A[j+k+mid]=(x-y+mod)%mod;
			}
		}
	}
}

signed main(){
	inv3=powi(3,mod-2);
	//cout<<inv3<<endl; 
	for(int i=1;i<=600;i<<=1)
	powi3[i]=powi(3,(mod-1)/i),powinv3[i]=powi(inv3,(mod-1)/i);
	while(getline(cin,t)){
		limit=1;len=0;
		memset(rev,0,sizeof(rev));
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		int tot=0,now=0,cheng=0;
		int lena=0,lenb=0;
		//printf("%s\n",t);
		for(int i=0;i<(int)t.length();){
			//cout<<t[i]<<endl;
			if(t[i]=='('){
				//cout<<"Case 1 start "<<endl;
				memset(s,0,sizeof(s));
				tot=0;++now;
				i++;
			}else if(t[i]==')'){
				//cout<<"Case 2 endi "<<endl;
				sort(s+1,s+1+tot);
				//cout<<"tot "<<tot<<endl;
				//for(int j=1;j<=tot;j++)cout<<s[j].x<<" "<<s[j].y<<endl;
				for(int j=1;j<=tot;j++)
				if(now==1)a[s[j].y]=s[j].x,lena=max(lena,s[j].y);
				else if(now==2)b[s[j].y]=s[j].x,lenb=max(lenb,s[j].y);
				i++;
			}else if(t[i]=='*')i++,++cheng;
			else if(t[i]==' ')i++;
			else{
				//cout<<"Case 3 mid "<<endl;
				int x=0;
				while(t[i]>='0'&&t[i]<='9'){
					x=x*10+t[i]-'0';i++;
				}
				++tot;
				s[tot].x=x;
				if(t[i]!=')'){
					i+=2;
					x=0;
					while(t[i]>='0'&&t[i]<='9'){
						x=x*10+t[i]-'0';i++;
					} 
					s[tot].y=x;
				}
				if(t[i]=='+')i++;
			}
		}
		if(!cheng){
			cout<<t<<endl;
			continue;
		}
		//cout<<lena<<" "<<lenb<<endl;
		//cout<<"lena "<<lena<<" lenb "<<lenb<<endl;
		//cout<<"a "<<endl;
		//for(int i=0;i<=lena;i++)cout<<a[i]<<" ";cout<<endl;
		//cout<<"b "<<endl;
		//for(int i=0;i<=lenb;i++)cout<<b[i]<<" ";cout<<endl;
		while(limit<=lena+lenb)limit<<=1,++len;
		for(int i=0;i<limit;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(len-1));
		//cout<<"Case 1 "<<endl;
		NTT(a,1);NTT(b,1);
		//cout<<"Case 2 "<<endl;
		for(int i=0;i<limit;i++)a[i]=a[i]*b[i]%mod;
		NTT(a,-1);
		inv=powi(limit,mod-2);
		for(int i=0;i<=lena+lenb;i++)a[i]=a[i]*inv%mod;
		//for(int i=0;i<=lena+lenb;i++)cout<<a[i]<<" ";cout<<endl;
		int n=lena+lenb+2;
		while(a[n]==0)--n;
		cheng=0;
		while(a[cheng]==0)++cheng;
		for(int i=n;i>=0;i--)
		if(i>0&&a[i]>0){
			printf("%da^%d",a[i],i);
			if(cheng!=i)printf("+");
		}else if(i==0&&a[i])printf("%d",a[i]);
		cout<<endl;
	}
}

P3338 [ZJOI2014]力(FTT模板1.0)

https://www.luogu.com.cn/problem/P3338

不知道为什么,重构一遍就过了……

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<bits/stdc++.h>
using namespace std;

const int N=4e5+10;
const double pi=acos(-1.0);
int n,limit=1,len,rev[N];
struct node{
	double x,y;
	node(double xi=0,double yi=0){
		x=xi;y=yi;
	}
	node operator +(const node &b)const{
		return {x+b.x,y+b.y};
	}
	node operator -(const node &b)const{
		return {x-b.x,y-b.y};
	}
	node operator *(const node &b)const{
		return {x*b.x-y*b.y,x*b.y+y*b.x};
	}
}H[N],G[N],I[N];

inline void FFT(node *A,double flag){
	for(int i=0;i<limit;i++)if(i<rev[i])swap(A[i],A[rev[i]]);
	for(int mid=1;mid<limit;mid<<=1){
		node Wn={cos(pi/mid),flag*sin(pi/mid)};
		for(int j=0;j<limit;j+=(mid<<1)){
			node W={1.0,0};
			for(int k=0;k<mid;k++,W=W*Wn){
				node x=A[j+k],y=A[j+k+mid]*W;
				A[j+k]=x+y;
				A[j+k+mid]=x-y;
			}
		}
	}
}

signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>H[i].x;
		G[n-i+1].x=H[i].x;
		I[i].x=(double)1/(double)i/(double)i;
	}
	while(limit<=(n<<1))limit<<=1,++len;
	for(int i=0;i<limit;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(len-1));
	FFT(H,1);FFT(G,1);FFT(I,1);
	for(int i=0;i<=limit;i++)H[i]=H[i]*I[i],G[i]=G[i]*I[i];
	FFT(H,-1);FFT(G,-1);
	for(int i=0;i<=limit;i++)H[i].x/=limit,G[i].x/=limit;
	for(int i=1;i<=n;i++)printf("%.4lf\n",H[i].x-G[n-i+1].x);
	return 0;
}

\[\lfloor \quad \rfloor\\ \]

 posted on 2022-04-15 20:49  eleveni  阅读(129)  评论(0)    收藏  举报