[洛谷P1919 A*B Problem] [FFT板子题]

FFT就不多说了吧,反正已经有写得很好的blog了,强烈推荐去看menci的FFT学习笔记,写得十分详细,条理也很清晰,我就是看这个才懂FFT的!!(传送门:menci FFT学习笔记

这里只是想提几个注意点。

[1] 蝴蝶操作需谨慎,就是将每个a[i]映射到对应位置的时候,由于二进制的位置从0开始标号,容易搞错;

[2] 自定义的operator运算最好加括号,防止优先级的问题

[3] 最后a[i]/n应该改成(a[i]+0.5)/n,因为由于精度误差,可能a[i]/n出现12.9999/13这种情况,导致整除的时候结果比原来小。

[4] 中途迭代的时候下标不能搞错,我一开始就把a[i+l]写成a[i]了。

FFT不容易调试,能读程序找错最好,不能的话只好出几个样例来看了,要细心一点。

#include <cstdio>
#include <cmath>
#include <cstring>
#define db double
#define rep(i,j,k) for (i=j;i<=k;i++)
#define down(i,j,k) for (i=j;i>=k;i--)
using namespace std;
const int N=12e5+5;
const db PI=acos(-1.0);
char sa[N],sb[N];
struct cpl{
	db a,b;
	cpl () { a=b=0; }
	cpl (db aa,db bb) { a=aa; b=bb; }
	cpl operator + (const cpl &B) {	return cpl(a+B.a,b+B.b); }
	cpl operator - (const cpl &B) {	return cpl(a-B.a,b-B.b); }
	cpl operator * (const cpl &B) {	return cpl(a*B.a-b*B.b,a*B.b+b*B.a); }
}A[N],B[N],C[N];
struct large{
	int n,d[N];
	cpl a[N];
	int pos(int x,int K)
	{
		int i,ret=0;
		rep(i,0,K-1)
			if (x&(1<<i)) ret+=(1<<(K-i-1));
		return ret;
	}
	void FFT(cpl *A,int K,int sgn) //K-positions
	{
		int i,l,m,k,len=1<<K;
		cpl bsc,w,L,R;
		rep(i,0,len-1) a[pos(i,K)]=A[i]; 
		for (k=2;k<=len;k<<=1)
		{
			m=k/2; bsc=cpl(cos(2*PI/k),sgn*sin(2*PI/k));
			for (l=0;l<len;l+=k)
			{
				w=cpl(1,0);
				rep(i,0,m-1)
				{
					L=a[l+i]; R=a[l+m+i];
					a[l+i]=L+(w*R); //ÓÅÏȼ¶!! 
					a[l+i+m]=L-(w*R);
					w=w*bsc;
				}
			}
		}
		rep(i,0,len-1)
			if (sgn==1) A[i]=a[i];
			else A[i]=cpl((a[i].a+0.5)/len,0); //·ÀÖ¹³öÏÖ12.99999ÕâÑùµÄ¾«¶ÈÎó²î,Òª+0.5 
	}
	void mult (const large &Y,large &ret)
	{
		int i,k,len=n+Y.n-1;
		for (k=0;(1<<k)<len;k++);
		len=1<<k; //0~len-1
		rep(i,0,len-1) A[i]=cpl(d[i],0),B[i]=cpl(Y.d[i],0);
		FFT(A,k,1);
		FFT(B,k,1);
		rep(i,0,len-1) C[i]=A[i]*B[i];
		FFT(C,k,-1); ret.n=len;
		rep(i,0,len-1) ret.d[i]=C[i].a;
		rep(i,0,ret.n-1)
		{
			if (ret.d[i]>9)
			{
				if (i==ret.n-1) ret.n++;
				ret.d[i+1]+=ret.d[i]/10;
				ret.d[i]%=10;
			}
		}
		for (;ret.n>1 && !ret.d[ret.n-1];ret.n--);
	}
}numA,numB,ans;
int n,i;
int main()
{
	scanf("%d",&n); numA.n=numB.n=n;
	scanf("%s%s",sa,sb);
	rep(i,0,n-1) numA.d[i]=sa[n-i-1]-'0',numB.d[i]=sb[n-i-1]-'0';
	numA.mult(numB,ans);
	down(i,ans.n-1,0) printf("%d",ans.d[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Orzage/article/details/84579809
ab