题解 P1919 【【模板】A*B Problem升级版(FFT快速傅里叶)】
介绍一种并不能过题的Karatsuba 乘法。
假设我们要求x*y,我们让:
那么
又因为
所以我们可以重复利用ac和bd的结果,不用做四次乘法。 这样递归下去求的复杂度是 (来自百度百科)
下面是这个算法本蒟蒻的代码实现
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int L=120010;
string add(string a,string b)
{
string ans;
int na[L]={0},nb[L]={0};
int la=a.size(),lb=b.size();
for(int i=0;i<la;i++) na[la-1-i]=a[i]-'0';
for(int i=0;i<lb;i++) nb[lb-1-i]=b[i]-'0';
int lmax=la>lb?la:lb;
for(int i=0;i<lmax;i++) na[i]+=nb[i],na[i+1]+=na[i]/10,na[i]%=10;
if(na[lmax]) lmax++;
for(int i=lmax-1;i>=0;i--) ans+=na[i]+'0';
return ans;
}
string sub(string a,string b)
{
string ans;
int na[L]={0},nb[L]={0};
int la=a.size(),lb=b.size();
for(int i=0;i<la;i++) na[la-1-i]=a[i]-'0';
for(int i=0;i<lb;i++) nb[lb-1-i]=b[i]-'0';
int lmax=la>lb?la:lb;
for(int i=0;i<lmax;i++)
{
na[i]-=nb[i];
if(na[i]<0) na[i]+=10,na[i+1]--;
}
while(!na[--lmax]&&lmax>0) ;lmax++;
for(int i=lmax-1;i>=0;i--) ans+=na[i]+'0';
return ans;
}
//---------------------大数加减法---------------------------------//
string karatsuba(string a,string b){
if(a.size()<b.size()) swap(a,b);
int tmp=a.size()-b.size();
string qd0="";for(int i=0;i<tmp;i++) qd0+='0';
b=qd0+b;
//---------------补前导0------------------//
if(a.size()==b.size()&&a.size()==1){
string ans="";
int ansnum=(a[0]-48)*(b[0]-48);
while(ansnum){ans=(char)('0'+ansnum%10)+ans;ansnum/=10;}
if(ans.size()==0) ans="0";
return ans;
}
int mid=a.size()-a.size()/2;
string qa,ha,qb,hb;
qa=a.substr(0,mid);ha=a.substr(mid,a.size()-mid);
qb=b.substr(0,mid);hb=b.substr(mid,b.size()-mid);
string qaqb=karatsuba(qa,qb);
string hahb=karatsuba(ha,hb);
string qahbhaqb=sub(karatsuba(add(qa,ha),add(qb,hb)),add(qaqb,hahb));
//------------------三次乘法---------------------------//
for(int i=0;i<(a.size()-mid)*2;i++) qaqb+='0';
for(int i=0;i<(a.size()-mid);i++) qahbhaqb+='0';
//------------------移位------------------------------//
string ans=add(qaqb,qahbhaqb);
ans=add(ans,hahb);
return ans;
}
int main(){
int n;cin>>n;
string a,b;cin>>a>>b;
cout<<karatsuba(a,b)<<endl;
return 0;
}