您的位置:首页 > 其它

【51NOD1028】大数乘法 V2

2017-02-16 17:29 411 查看

╰( ̄▽ ̄)╭

给出2个大整数A,B,计算A*B的结果。

(A,B的长度 <= 100000,A,B >= 0)

(⊙ ▽ ⊙)

把大整数A看做一个次数界为lenA的多项式A(x),其中x=10,

同样,把B看做一个次数界为lenB的多项式B(x),其中x=10。

然后套上快速傅里叶变换

( ̄~ ̄)

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
const char* fin="ftt.in";
const char* fout="fttx.out";
const int inf=0x7fffffff;
const double pi=acos(-1),eps=10e-6;
const int maxn=400007;
struct Z{
double x,y;
Z(double _x=0,double _y=0){x=_x;y=_y;}
Z operator +(const Z &b){return Z(x+b.x,y+b.y);}
Z operator -(const Z &b){return Z(x-b.x,y-b.y);}
Z operator *(const Z &b){return Z(x*b.x-y*b.y,x*b.y+y*b.x);}
}a[maxn],b[maxn],t[maxn];
int ans[maxn],lena,lenb,n,N,i,j,k;
void read(Z *a,int &len){
int i,j,k;
char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9') a[len++]=ch-'0',ch=getchar();
for (i=0;i<(len+1)/2;i++) swap(a[i],a[len-i-1]);
}
void getn(){
int i,j,k=max(lena,lenb);
for (n=1;n<k;n<<=1) N++;
n<<=1;N++;
}
int fan(int v){
int i=N,k=0;
while (i--){
k=(k<<1)+(v&1);
v>>=1;
}
return k;
}
void fft(Z *a,int sig){
int i,j,k,m;
for (i=0;i<n;i++) t[fan(i)]=a[i];
for (m=2;m<=n;m<<=1){
int ha=m/2;
for (i=0;i<ha;i++){
Z w(cos(i*sig*pi/ha),sin(i*sig*pi/ha));
for (j=i;j<n;j+=m){
Z u=t[j],v=w*t[j+ha];
t[j]=u+v;
t[j+ha]=u-v;
}
}
}
for (i=0;i<n;i++) a[i]=t[i];
}
int main(){
freopen(fin,"r",stdin);
freopen(fout,"w",stdout);
read(a,lena);read(b,lenb);
getn();

fft(a,1);
fft(b,1);
for (i=0;i<n;i++) a[i]=a[i]*b[i];
fft(a,-1);

for (i=0;i<=n;i++){
ans[i]+=int(a[i].x/n+eps);
ans[i+1]+=ans[i]/10;
ans[i]%=10;
}
while (!ans
) n--;
for (;n>=0;n--) printf("%d",ans
);
return 0;
}


(⊙v⊙)

Pay Attention

1.read()中,不要把len打成lena;
翻转大整数时,是从0枚举到(len+1)/2;

2.getn()中,n最后要再乘一次2,因为:
A*B的次数界是lena*lenb。

3.maxn要开到4倍;

4.pi=acos(-1);

5.当对一个小数x用int()取整时,需要打成int(x+eps),其中,eps=10e-6。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: