FFT(快速傅里叶变换)NTT(快速数论变换)模板

文章目录

FFT

模板题:51nod 1028大数乘法
给一个更快的方法

void DFT(node *a,int sig)
{
	fo(i,0,len-1)
	{
		int p=0;
		for(int j=0,tp=i;j<lg;j++,tp/=2) p=(p<<1)+(tp%2);
		d[p]=a[i];
	}
	for(int m=2;m<=len;m*=2)
	{
		int half=m/2,tmp=len/m;
		for(int j=0;j<len;j+=m)
		{
			fo(i,j,j+half-1)
			{
				node u=d[i],v=d[i+half]*W[sig==1?(i-j)*tmp:len-(i-j)*tmp];
				d[i]=u+v;
				d[i+half]=u-v;
			}
		}
	}
	if(sig==-1) fo(i,0,len-1) d[i].x/=len;
	fo(i,0,len-1) a[i]=d[i];
}
void FFT(node *a,node *b,ll *c)
{
	fo(i,0,len) W[i].x=cos(i*pi*2.0/len),W[i].y=sin(i*pi*2.0/len);
	W[0].x=1,W[0].y=0;W[1].x=cos(pi*2/len),W[1].y=sin(pi*2/len);
	fo(i,2,len) W[i]=W[i-1]*W[1];
	fo(i,0,len-1) q1[i].x=(ll)a[i].x/gm,q2[i].x=(ll)a[i].x%gm,q1[i].y=q2[i].y=0;
	fo(i,0,len-1) q3[i].x=(ll)b[i].x/gm,q4[i].x=(ll)b[i].x%gm,q3[i].y=q4[i].y=0;
	DFT(q1,1);DFT(q2,1);DFT(q3,1);DFT(q4,1);
	fo(i,0,len-1) q[i]=q1[i]*q3[i];
	DFT(q,-1);
	fo(i,0,len-1) c[i]=(ll)(q[i].x+0.5)%mo*gm%mo*gm%mo;
	fo(i,0,len-1) q[i]=q1[i]*q4[i]+q2[i]*q3[i];
	DFT(q,-1);
	fo(i,0,len-1) c[i]=(c[i]+(ll)(q[i].x+0.5)%mo*gm)%mo;
	fo(i,0,len-1) q[i]=q2[i]*q4[i];
	DFT(q,-1);
	fo(i,0,len-1) c[i]=(c[i]+(ll)(q[i].x+0.5))%mo;
}
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define db double
#define N 401000
using namespace std;
struct node{
	db x,y;
	node friend operator +(node a,node b){node c;c.x=a.x+b.x;c.y=a.y+b.y;return c;}
	node friend operator -(node a,node b){node c;c.x=a.x-b.x;c.y=a.y-b.y;return c;}
	node friend operator *(node a,node b){node c;c.x=a.x*b.x-a.y*b.y;c.y=a.x*b.y+a.y*b.x;return c;}
};
int len,lg,n,m;
long long ans[N];
db c[N],pi;
node a[N],b[N],q[N],w[N],d[N];
void init()
{
	char c=getchar();m=-1;
	for(;c>='0'&&c<='9';c=getchar()) b[++m].x=c-48;
}
void DFT(node *a,int sig)
{
	fo(i,0,len-1)
	{
		int p=0;
		for(int j=0,tp=i;j<lg;j++,tp/=2) p=(p<<1)+(tp%2);
		d[p]=a[i];
	}
	for(int m=2;m<=len;m*=2)
	{
		int half=m/2;
		fo(i,0,half-1)
		{
			node w;
			w.x=cos(i*sig*pi/half),w.y=sin(i*sig*pi/half);
			for(int j=i;j<len;j+=m)
			{
				node u=d[j],v=d[j+half]*w;
				d[j]=u+v;
				d[j+half]=u-v;
			}
		}
	}
	if(sig==-1) fo(i,0,len-1) d[i].x/=len;
	fo(i,0,len-1) a[i]=d[i];
}
void FFT(node *a,node *b,db *c)
{
	fo(i,0,len-1) q[i]=a[i],w[i]=b[i];
	DFT(q,1);DFT(w,1);
	fo(i,0,len-1) q[i]=q[i]*w[i];
	DFT(q,-1);
	fo(i,0,len-1) c[i]=q[i].x;
}
int main()
{
	freopen("fft.in","r",stdin);
	freopen("fft.out","w",stdout);
	init();
	n=m;fo(i,0,n) a[i]=b[i];
	init();
	for(len=1;len<n+m;len*=2);
	lg=log2(len);pi=acos(-1);
	fo(i,0,n/2) swap(a[i],a[n-i]);
	fo(i,0,m/2) swap(b[i],b[m-i]);
	fo(i,m+1,n) b[i].x=b[i].y=0;
	FFT(a,b,c);
	n=len;
	fo(i,0,n-1) ans[i]=round(c[i]);
	fo(i,0,n-1) ans[i+1]+=ans[i]/10,ans[i]%=10;
	for(;ans[n]==0;n--);
	for(int i=n;i>=0;i--) printf("%lld",ans[i]);
}

NTT

模板题:51nod 1348 乘积之和

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 70100
#define ll long long
#define db double
#define mod 100003
#define mo1 998244353ll
#define mo2 1004535809ll
using namespace std;
int n,ac,len,v[N];
ll c[20][2][N],q[N],w[N],d[N],b[20][N],a[2][N],W[N];
ll M=mo1*mo2,ni1,ni2;
db lg;
ll mi(ll a,ll b,ll mo)
{
	a%=mo;ll jy=1;
	for(;b;b/=2,a=a*a%mo) if(b%2==1) jy=jy*a%mo;
	return jy;
}
ll mul(ll a,ll b)
{
	ll jy=0;
	for(;b;b/=2,a=(a+a)%M) if(b%2==1) jy=(jy+a)%M;
	return jy;
}
void DFT(ll *a,int sig,ll mo)
{
	fo(i,0,len-1)
	{
		int p=0;
		for(int j=0,tp=i;j<lg;j++,tp/=2) p=(p<<1)+(tp%2);
		d[p]=a[i];
	}
	for(int m=2;m<=len;m*=2)
	{
		int half=m/2,tmp=len/m;
		fo(i,0,half-1)
		{
			ll w=(sig==1)?W[i*tmp]:W[len-i*tmp];
			for(int j=i;j<len;j+=m)
			{
				ll u=d[j],v=d[j+half]*w%mo;
				d[j]=(u+v)%mo;
				d[j+half]=(u-v+mo)%mo;
			}
		}
	}
	fo(i,0,len-1) a[i]=d[i];
}
void NTT(ll *a,ll *b,ll *c,ll mo)
{
	W[0]=1;W[1]=mi(3,(mo-1)/len,mo);
	fo(i,2,len) W[i]=W[i-1]*W[1]%mo;
	fo(i,0,len-1) q[i]=a[i],w[i]=b[i];
	DFT(q,1,mo);DFT(w,1,mo);
	fo(i,0,len-1) q[i]=q[i]*w[i]%mo;
	DFT(q,-1,mo);
	ll inv=mi(len,mo-2,mo);
	fo(i,0,len-1) c[i]=q[i]*inv%mo;
}
void calc(int l,int r,int z)
{
	if(l==r)
	{
		b[z][0]=1;
		b[z][1]=v[l];
		return;
	}
	int m=(l+r)/2;
	calc(l,m,z+1);
	fo(i,0,m-l+1) c[z][0][i]=b[z+1][i];
	calc(m+1,r,z+1);
	fo(i,0,r-m) c[z][1][i]=b[z+1][i];
	for(len=1;len<r-l+3;len*=2);
	lg=log2(len);
	fo(i,m-l+2,len) c[z][0][i]=0;
	fo(i,r-m+1,len) c[z][1][i]=0;

	NTT(c[z][0],c[z][1],a[0],mo1);

	NTT(c[z][0],c[z][1],a[1],mo2);

	fo(i,0,len)
	{
		b[z][i]=((mul(a[0][i],ni1)+mul(a[1][i],ni2))%M)%mod;
	}
}
int main()
{
	scanf("%d%d",&n,&ac);
	fo(i,1,n) scanf("%d",&v[i]),v[i]%=mod;
	ni1=mi(mo2,mo1-2,mo1)*mo2;
	ni2=mi(mo1,mo2-2,mo2)*mo1;
	calc(1,n,0);
	for(;ac;ac--)
	{
		int x;scanf("%d",&x);
		printf("%lld\n",b[0][x]%mod);
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值