HDU 1402 fft 模板题
2015-10-26 12:19
501 查看
题目就是求一个大数的乘法
这里数字的位数有50000的长度,按平时的乘法方式计算,每一位相乘是要n^2的复杂度的,这肯定不行
我们可以将每一位分解后作为系数,如153 = 1*x^2 + 5*x^1 + 3*x^0 (在这里x可以理解成10)
那么两个数字相乘就相当于系数相乘后得到新的系数组合
如153 * 4987 = <3,5,1> * <7,8,9,4>
这相当于卷积的计算,最快的方式就是fft,nlgn的复杂度就能求解,求解得到后再把每一位大于10往前赋值就行了
这里数字的位数有50000的长度,按平时的乘法方式计算,每一位相乘是要n^2的复杂度的,这肯定不行
我们可以将每一位分解后作为系数,如153 = 1*x^2 + 5*x^1 + 3*x^0 (在这里x可以理解成10)
那么两个数字相乘就相当于系数相乘后得到新的系数组合
如153 * 4987 = <3,5,1> * <7,8,9,4>
这相当于卷积的计算,最快的方式就是fft,nlgn的复杂度就能求解,求解得到后再把每一位大于10往前赋值就行了
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <math.h> using namespace std; const double PI = acos(-1.0); struct complex{ double r , i; complex(double r=0 , double i=0):r(r),i(i){} complex operator+(const complex &a) const{ return complex(r+a.r , i+a.i); } complex operator-(const complex &a) const{ return complex(r-a.r , i-a.i); } complex operator*(const complex &a) const{ return complex(r*a.r-i*a.i , r*a.i+i*a.r); } }; void change(complex y[] , int len) { int i,j,k; for(i=1 , j=len/2 ; i<len-1 ; i++){ if(i<j) swap(y[i],y[j]); k = len/2; while(j>=k){ j-=k; k/=2; } if(j<k) j+=k; } } void fft(complex y[] , int len , int on) { change(y , len); for(int i=2 ; i<=len ; i<<=1){ complex wn(cos(-on*2*PI/i) , sin(-on*2*PI/i)); for(int j=0 ; j<len ; j+=i){ complex w(1,0); for(int k=j ; k<j+i/2 ; k++){ complex u = y[k]; complex t = w*y[k+i/2]; y[k] = u+t; y[k+i/2] = u-t; w = w*wn; } } } if(on==-1) for(int i=0 ; i<len ; i++) y[i].r /= len; } const int MAXN = 200010; complex x1[MAXN] , x2[MAXN]; char str1[MAXN] , str2[MAXN]; int sum[MAXN]; int main() { while(~scanf("%s%s" , str1 , str2)){ int len1 = strlen(str1) , len2 = strlen(str2); int len = 1; //fft的计算,由于是倍增的,需要保证是2^k次方,且要大于最后得到的结果的总位数 while(len<len1*2 || len<len2*2) len<<=1; for(int i=0 ; i<len1 ; i++) x1[i] = complex(str1[len1-1-i]-'0' , 0); for(int i=len1 ; i<len ; i++) x1[i] = complex(0 , 0); for(int i=0 ; i<len2 ; i++) x2[i] = complex(str2[len2-1-i]-'0' , 0); for(int i=len2 ; i<len ; i++) x2[i] = complex(0 , 0); //将当前的组合数的系数值修改成复数坐标系的点值o(nlgn) fft(x1 , len , 1); fft(x2 , len , 1); //点值可以o(n)的时间内进行计算 for(int i=0 ; i<len ; i++) x1[i] = x1[i]*x2[i]; //将点值重新通过逆过程(又叫dft)转化为系数值 fft(x1 , len , -1); memset(sum , 0 , sizeof(sum)); for(int i=0 ; i<len ; i++) sum[i] = (int)(x1[i].r+0.5); for(int i=0 ; i<len ; i++){ sum[i+1] += sum[i]/10; sum[i] = sum[i]%10; } int ansl = len1+len2-1; while(sum[ansl]==0 && ansl>0) ansl--; for(int i=ansl ; i>=0 ; i--) printf("%c" , sum[i]+'0'); printf("\n"); } return 0; }
相关文章推荐
- Codeforces Round #327 (Div. 2) A. Wizards' Duel 反思
- scala List
- Android网络编程http派/申请服务
- scala数组操作
- 解析中间人攻击之四——SSL欺骗
- IOS 然你的新建的view 盖住系统键盘的做法
- 汉字转拼音
- UITextField学习技巧
- triple Des加密之ECB加密解密、CBC加密解密
- codeforces 591 D. Chip 'n Dale Rescue Rangers
- UIAlertController
- 通过网卡名字获取ip
- 编写一个函数itob(int n,char s[], int b),将整数n转换为以b进制的数。保存到s中。
- 机房收费系统----用例图
- 从github下载某个git库的4种方式
- 音乐播放器时间
- Linux中ifreq 结构体分析和使用(转)
- 14.3 Using Partitioned Indexes for Performance 使用分区索引
- C++面试常见题目问与答(汇总一)
- ERROR ITMS-90049:"This bundle is invalid.The bundle identifier contains disallowed characters."