UOJ 34 多项式乘法 ——NTT

【题目分析】

    快速数论变换的模板题目。

    与fft的方法类似,只是把复数域中的具有循环性质的单位复数根换成了模意义下的原根。

    然后和fft一样写就好了,没有精度误差,但是跑起来比较慢。

    这破题目改了好长时间,吃枣药丸。

【代码】

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int md=998244353;
const int g=3;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long 
#define maxn 400005
int n,m,rev[maxn],len=0,top;
int a[maxn],b[maxn],c[maxn];

int _pow(int a,int b)
{
	int ret=1;
	while (b)
	{
		if (b&1) ret=(ll)ret*a%md;
		a=(ll)a*a%md;
		b>>=1;
	}
	return ret;
}

void NTT(int * x,int n,int f)
{
	F(i,0,n-1) if (rev[i]>i) swap(x[i],x[rev[i]]);
	for (int m=2;m<=n;m<<=1)
	{
		int wn=_pow(g,(md-1)/m);
		if (f) wn=_pow(wn,md-2);
		for (int i=0;i<n;i+=m)
		{
			int w=1;
			F(j,0,(m>>1)-1)
			{
				int u=x[i+j],v=(ll)x[i+j+(m>>1)]*w%md;
				x[i+j]=(u+v)%md;
				x[i+j+(m>>1)]=((u-v)%md+md)%md;
				w=(ll)w*wn%md;
			}
		}
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	F(i,0,n) scanf("%d",&a[i]);
	F(i,0,m) scanf("%d",&b[i]);
	n=n+m+1;m=1;
	top=n+m-1;
	while (m<=n) m<<=1,len++; n=m;
	F(i,0,n-1)
	{
		int ret=0,t=i;
		F(j,1,len) ret<<=1,ret|=t&1,t>>=1;
		rev[i]=ret;
	}
	NTT(a,n,0); NTT(b,n,0);
	F(i,0,n-1) c[i]=(ll)a[i]*b[i]%md;
	NTT(c,n,1);
	int tmp=_pow(n,md-2);
	F(i,0,top-1) printf("%d ",(ll)c[i]*tmp%md);
}

  

原文地址:https://www.cnblogs.com/SfailSth/p/6422532.html