洛谷 P1919 【模板】A*B Problem升级版 【快速傅里叶变换 FFT】

【洛谷 P1919】 【模板】A*B Problem升级版

题目大意

给你两个超大整数 a , b a,b a,b,问 a ∗ b a*b a∗b
其中 a , b ≤ 1 0 1000000 a,b\leq10^{1000000} a,b≤101000000

思路

高精度都是狗
很明显,我们普通的高精度乘法不知道炸到哪里去了。
我们发现对于一个 n n n 位的十进制数 K K K,我们可以看做一个 n − 1 n-1 n−1 次的多项式,表示成 A ( x ) = a 0 + a 1 ∗ 10 + a 2 ∗ 1 0 2 + ⋅ ⋅ ⋅ + a n − 1 ∗ 1 0 n − 1 A(x)=a_0+a_1*10+a_2*10^2+···+a_{n-1}*10^{n-1} A(x)=a0​+a1​∗10+a2​∗102+⋅⋅⋅+an−1​∗10n−1
这样我们就可以把两个多项式卷积,就是乘起来, F F T FFT FFT 准备报到!

注意几个小细节:

为了方便,我们要把数倒序存储,因为我们在做 F F T FFT FFT 的时候多项式每一项的次数是递增的,而这里数的存储是从高位往低位存的,所以要逆序存储。
注意在加法的时候处理进位和前导 0 0 0
F F T FFT FFT 板子一定要背熟 (逃)

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cmath>
#define r register
#define rep(i,x,y) for(r ll i=x;i<=y;++i)
#define per(i,x,y) for(r ll i=x;i>=y;--i)
using namespace std;
typedef long long ll;
const ll V=3e6+10;
const double pi=acos(-1.0); 
ll in()
{
	ll res=0,f=1;
	char ch;
	while((ch=getchar())<'0'||ch>'9')
	 if(ch=='-') f=-1;
	res=res*10+ch-48;
	while((ch=getchar())>='0'&&ch<='9')
	 res=res*10+ch-48;
	return res*f;
}
ll n,m,f[V];
ll now,k,ans[V];
char s1[V],s2[V];
struct complex 
{
	double x,y;//对应复数 a+bi 
	complex (double xx=0,double yy=0) { x=xx,y=yy; }
}a[V],b[V];
complex operator + (complex a,complex b) { return complex(a.x+b.x,a.y+b.y); }
complex operator - (complex a,complex b) { return complex(a.x-b.x,a.y-b.y); }
complex operator * (complex a,complex b) { return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x); }
void FFT(complex *a,ll v)
{
	rep(i,0,now-1)
	 if(i<f[i]) swap(a[i],a[f[i]]);
	for(r ll mid=1;mid<now;mid<<=1)
	{
		complex Wn(cos(pi/mid),v*sin(pi/mid));//单位根 
		ll R=mid<<1;
		for(r ll j=0;j<now;j+=R)
		{
			complex val(1,0);
			for(r ll k=0;k<mid;++k,val=val*Wn)
			{
				complex x=a[j+k],y=val*a[j+mid+k];
				a[j+k]=x+y;
				a[j+mid+k]=x-y;
			}
		}
	}
}//这里和模板 FFT 一模一样
int main()
{
	scanf("%s%s",s1,s2);
	n=strlen(s1),m=strlen(s2);
	rep(i,0,n-1) a[i].x=(double)(s1[n-i-1]-'0');
	rep(i,0,m-1) b[i].x=(double)(s2[m-i-1]-'0');
	now=1;//单位根中的k值,默认为2的自然数次幂 
	while(now<=n+m) now<<=1,++k;
	rep(i,0,now-1)
	 f[i]=(f[i>>1]>>1)|((i&1)<<(k-1));//背板子做笔记 !!! 
	FFT(a,1);
	FFT(b,1);
	rep(i,0,now) a[i]=a[i]*b[i];
	FFT(a,-1);
	rep(i,0,now)
	{
		ans[i]+=(ll)(a[i].x/now+0.49);
		if(ans[i]>=10)
		{
			ans[i+1]+=(ans[i]/10),ans[i]%=10;
			if(i==now) ++now;
		}
	}
	while(ans[now]==0&&now>=1) --now;
	per(i,now,0) putchar(ans[i]+'0');
	return 0;
}
上一篇:python 2.7 ImportError: No module named numpy


下一篇:聊聊21电赛A题以及涉及到的信号知识