快速傅里叶变换

18 篇文章 0 订阅
6 篇文章 0 订阅

呜呜呜不要来北理上学

写在前面的话:

  • 没有啦,想打ACM反正迟早都是要学的。
  • 废寝忘食苦学了两天,终于照着板子+魔鬼调试敲过了大整数乘法。
  • 真的好难,还好我们会用板子就可以啦。
  • 看了许多BLOG,将真正写的非常好很有帮助的贴出来:
    Leo_h1104
    GGN_2015
    GGN_2015
    Duan2baka
    路人黑的纸巾
    Leo先生写的真是太棒啦!
    本文是我给自己做个总结,由于讲的好的BLOG远少于讲的差的,我也不一定能讲好,各位看上面这些就够了。
  • 呜呜呜不会用LaTex,就手写啦,尽量写的好看吼。
  • 一定要看先知道数学原理,才能看懂代码。

一:数学:

  • 先要明确,FFT是要将多项式的系数表达法转为点值表达法。至于为什么/什么意思,下面并不提及,需要您看上面的BLOG。如我所说,本文的定位是总结。
    一
    二
    三

四

板子:

  • 容器、定义
const int maxn = 1e5 + 5;
typedef complex<double> cd;
const double PI = 3.1415926535;

cd A[maxn * 5] , B[maxn * 5];//两个多项式的系数点集,DFT后转成点值点集,IDFT后转回系数点集 
int rev[maxn * 5]; 
int MulAns[maxn * 5];//存结果的系数集 
  • 每个位置分治后的最终位置是它二进制翻转后得到的位置,用于迭代
void GetRev(int bit){
	memset(rev , 0 , sizeof(rev));
	for(int i=0;i<(1<<bit);i++)
		rev[i] = (rev[i>>1]>>1) | ((i&1)<<(bit-1));
	return ;
}
  • DFT or IDFT
//数组名、2^、DFT/IDFT 
void FFT(cd *a,int ran,int dft){
	//dft=1:正变换;dft=-1:逆变换
	for(int i=0;i<ran;i++)
		if(i < rev[i])
			swap(a[i] , a[rev[i]]);
	for(int step=1;step<ran;step<<=1){
		//自底向上模拟分治
		//一共有len个系数 
		cd Wn = exp(cd(0 , dft*PI/step));//e^(i * (2PI/N));//N=2*step 
		for(int i=0;i<ran;i+=(step<<1)){
			//针对本层的所有块分别处理,每次两块 
			cd Wnk(1 , 0); 
			for(int j=i;j<i+step;j++){
				//蝴蝶变幻 
				cd l=a[j];
				cd r=Wnk*a[j+step];
				a[j] = l+r;
				a[j+step] = l-r;
				Wnk *= Wn; 
			}
		}
	}
	if(dft == -1)
		for(int i=0;i<ran;i++)
			a[i]/=ran;
	return ;
}
  • 大整数乘法
void MUL(){
	memset(A , 0 , sizeof(A));
	memset(B , 0 , sizeof(B));//补零,最重要的初始化! 
	memset(MulAns , 0 , sizeof(MulAns));	
	int bit=1;//ran = 2^bit
	int ran=(1<<1);//range;比如结果有1e4+5位,那么ran就是大于1e4+5且是2^bit。 
	for(bit=1 ; ran<len1+len2; bit++)
		ran<<=1;
	for(int i=0;i<len1;i++)
		A[i] = (double)(L[len1-i-1] - '0');//顺便reverse
	for(int i=0;i<len2;i++)
		B[i] = (double)(R[len2-i-1] - '0');
	
	
	GetRev(bit);
	FFT(A,ran,1) , FFT(B,ran,1);//DFT
	for(int i=0;i<ran;i++)
		A[i] *= B[i];
	FFT(A,ran,-1);//IDFT
	
	
	for(int i=0;i<ran;i++){
		MulAns[i] += (int)(A[i].real() + 0.5);//精度
		MulAns[i+1] += MulAns[i]/10;
		MulAns[i] %= 10;
	}
	int i;
	for(i=ran-1;i>=0;i--)
		if(MulAns[i])
			break;
		else
			;
	if(i < 0)
		printf("0");
	else
		for(i;i>=0;i--)
			printf("%d" , MulAns[i]);
	printf("\n");
	return ;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值