HDU1402 FFT大数乘法

3 篇文章 0 订阅

A * B Problem Plus

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 28421    Accepted Submission(s): 7712

 

Problem Description

Calculate A * B.

 

Input

Each line will contain two integers A and B. Process to end of file.

Note: the length of each integer will not exceed 50000.

 

Output

For each case, output A * B in one line.

 

Sample Input

1 2

1000 2

 

Sample Output

2

2000

 

FFT入门板题。

大数乘法,A = a0*10^0 + a1*10^1 +...+ ai*10^i + ... B同理

故可用多项式乘法。

FFT用完以后要处理进位,还要注意0的输出,具体看代码注释:)

 

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

typedef long long LL;
const double pi=acos(-1.0);
const LL maxn=1e5+10;

struct complex
{
	double re,im;
	complex(double r=0.0,double i=0.0) {re=r,im=i;}
	void print() {printf("%lf %lf\n",re,im);}///?输出debug?
};
complex operator +(const complex&A,const complex&B) {return complex(A.re+B.re,A.im+B.im);}
complex operator -(const complex&A,const complex&B) {return complex(A.re-B.re,A.im-B.im);}
complex operator *(const complex&A,const complex&B) {return complex(A.re*B.re-A.im*B.im,A.re*B.im+A.im*B.re);}

complex a[maxn<<1],b[maxn<<1],W[2][maxn<<1];//?maxn<<1的原因?n最大是nanb最大<<1

int n,na,nb,rev[maxn<<1];
char A[maxn],B[maxn];
int ans[maxn<<1];

void prework()
{
	n=1;
	while(n<na+nb) n<<=1;	//此题这个方法算n好嘤
	for(int i=0;i<n;++i){
		int x=i,y=0;
		for(LL k=1;k<n;x>>=1,k<<=1)
			(y<<=1)|=x&1;
		rev[i]=y;
	}
	for(int i=0;i<n;++i){
		W[0][i]=W[1][i]=complex(cos(2*pi*i/n),sin(2*pi*i/n));
		W[1][i].im=-W[0][i].im;
	}
}

void FFT(complex*a,int f)
{
	complex x,y;
	for(int i=0;i<n;++i)	//位逆序置换
		if(i<rev[i])	//只在遇到小的那个时交换一次
			swap(a[i],a[rev[i]]);
	for(int i=1;i<n;i<<=1){	//模拟合并过程//i可以想作步长
		for(int j=0,t=n/(i<<1);j<n;j+=i<<1){	//j每次跳到下一个需要合并的地方
			for(int k=0,l=0;k<i;++k,l+=t){	//"蝴蝶操作"
				x=W[f][l]*a[j+k+i];	//x相当于w*f1
				y=a[j+k];	//y相当于f2
				a[j+k]=y+x;		//f=f0+w*f1
				a[j+k+i]=y-x;	//f=f0-w*f1
			}
		}
	}
	if(f)
		for(int i=0;i<n;++i)
			a[i].re/=n;
}

int main()
{

	while(~scanf("%s%s",A,B)){
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		na=strlen(A);nb=strlen(B);
		for(int i=0;i<na;++i)
			a[i].re=A[na-i-1]-'0';	//注意从低位到高位存放!
		for(int i=0;i<nb;++i)
			b[i].re=B[nb-i-1]-'0';	//哭了,na、nb写成n了
        prework();
		FFT(a,0);FFT(b,0);	//分别得到a,b的点表示
		for(int i=0;i<n;++i)	//得到乘法结果c的点表示
			a[i]=a[i]*b[i];
		FFT(a,1);	//逆傅里叶变换得到结果多项式的各系数
		memset(ans,0,sizeof(ans));
		for(int i=0;i<n;++i){
			ans[i]+=(int)(a[i].re+0.5);	//取整误差处理
			ans[i+1]+=(ans[i]/10);	//处理进位!
			ans[i]%=10;
		}
		//注意输出格式,既不能输出前导0,也要输出后面的0
		n=na+nb;
		while(!ans[n]&&n) --n;//注意考虑0*0的情况!=0要有输出!
		for(int i=n;i>=0;--i){
			printf("%d",ans[i]);
		}
		printf("\n");
	}

	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值