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;
}