1. 程式人生 > >HDU - 1402 A * B Problem Plus FFT裸題

HDU - 1402 A * B Problem Plus FFT裸題

swa complex asn 直線 lse () strlen mod -i

http://acm.hdu.edu.cn/showproblem.php?pid=1402

題意:

  求$a*b$ 但是$a$和$b$的範圍可以達到 $1e50000$

題解:

  顯然...用字符串模擬的大數或者壓位的大數是無法勝任這種計算的....

  然後,2個大整數相乘,可以理解為卷積,所以就用快速傅裏葉變換(FFT)來加速他

  模板題

  簡單總結一下對FFT的認知:

FFT用於算卷積,卷積可以理解為兩個多項式相乘
顯然復雜度是$O(n^2)$的 但是fft可以優化為$O(nlogn)$
如何優化,
考慮2個點確定直線,3個點確定拋物線,$n+1$個點確定了$n$次多項式
我們用$n+1$個點$(x_i,y_i)$表達了原來的式子
如何用點值表達卷積(多項式相乘)?
式子展開可以知道,$x_i$確定的時候,對於點值表達式就對應了點$(x_i,f(x_i)*g(x_i))$
也就是可以$O(1)$得到一個點答案,$n$個點就是$O(n)$
那問題又來了,$n+1$個點的$(x_i,y_i)$,每次求解一次多項式的值,需要$O(n)$
也就是$O(n^2)$復雜度,依然超時
所以,現在考慮如何快速的算多項式的值
因為$x_i$我們可以自己定義,因此利用虛根的特殊性質,我們就能分治處理了
就可以復雜度$O(nlogn)$的得到點值表達式
然後$O(n)$的算點值表達式的值
然後逆運算回到答案

#include <bits/stdc++.h>
#define ll long long
#define usd unsigned
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define rep(ii,a,b) for(int ii=a;ii<=b;++i)
#define per(ii,a,b) for(int ii=b;ii>=a;--i)
#define show(x) cout<<#x<<"="<<x<<endl
#define show2(x,y) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<endl
#define show3(x,y,z) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl
#define show4(w,x,y,z) cout<<#w<<"="<<w<<" "<<#x<<"="<<x<<" "<<#y<<"="<<y<<" "<<#z<<"="<<z<<endl
#define showa(a,b) cout<<#a<<‘[‘<<b<<"]="<<a[b]<<endl
#define pii pair<int,int>
#define cp complex<double>//<complex>頭文件裏的東西
using namespace std;
const int maxn=2e5+10;
const int maxm=2e6+10;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
int casn,n,m,k;
const double pi=acos(-1.0);
int lena,lenb,len,pw,ans[maxn],rr[maxn];
cp a[maxn] ,b[maxn];
char sa[maxn],sb[maxn];
void fft(cp *a,int f){//遞歸分治太慢,用叠代實現
	rep(i,0,n-1) if(i<rr[i]) swap(a[i],a[rr[i]]);//分治原來的數組
	for(int i=1;i<n;i<<=1){
		cp wn(cos(pi/i),sin(f*pi/i)),x,y;//計算虛根
		for(int j=0;j<n;j+=(i<<1)){
			cp w(1,0);
			for(int k=0;k<i;++k,w*=wn){
				x=a[j+k],y=w*a[i+j+k];
				a[j+k]=x+y;
				a[i+j+k]=x-y;
			}
		}
	}
}
int main(){
	while(~scanf("%s%s",sa,sb)){
		n=1;
		len=pw=0;
		memset(ans,0,sizeof ans);
		lena=strlen(sa);
		lenb=strlen(sb);
		while(n<=lena+lenb) n<<=1,++pw;
		rep(i,0,lena-1) a[i]=sa[lena-i-1]-‘0‘;
		rep(i,lena,n) a[i]=0;
		rep(i,0,lenb-1) b[i]=sb[lenb-i-1]-‘0‘;
		rep(i,lenb,n) b[i]=0;
		rep(i,0,n) rr[i]=(rr[i>>1]>>1)|((i&1)<<(pw-1));//分治中的二進制規律,因此預處理參數
		fft(a,1);//DFT a
		fft(b,1);//DFT b
		rep(i,0,n) a[i]*=b[i];
		fft(a,-1);//IDFT a*b
		rep(i,0,lena+lenb) {
			ans[i]+=int(a[i].real()/n+0.5);
			ans[i+1]+=ans[i]/10;
			ans[i]%=10;
			if(ans[i]>0) len=i;
		}
		per(i,0,len){
			putchar (ans[i]+‘0‘);
		}
		puts("");
	}
  return 0;
}

  

HDU - 1402 A * B Problem Plus FFT裸題