码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 1402 A * B Problem Plus(快速傅里叶变换)

时间:2015-07-20 14:18:43      阅读:340      评论:0      收藏:0      [点我收藏+]

标签:

题意:两个数相乘,每个数的长度不超过10^5;

思路:FFT第一题。通过将系数表达式转换为点值表达式,降低复杂度;算导是个好东西!!!

        用DFT实现单位复根计算点值表达式,逆DFT则将点值表达式转为系数表达式,即计算插值;复杂度均为O(n^2);

        FFT采用分治的思想,将奇偶分开处理,优化DFT;复杂度为O(nlogn);

        FFT处理时,(将点值扩展到2^n)->(计算点值)->(点乘运算)->(计算插值);

 

        由于奇偶分治时结果的位置发生变化,需要在傅里叶变换时进行二进制位置互换;

        每经过一次蝴蝶操作DFT次数乘二,则控制层数;

        每次迭代使w的值不断变化可以节约每次通过for循环从0开始计算wn的时间;蝴蝶操作计算点值;

        DFT的逆计算插值;

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define pi acos(-1.0)
char str1[5000100],str2[5000100];
int num[5000100];
int len1,len2,n,m;
struct Complex{
    double r,i;
    Complex(){};
    Complex(double x,double y){
          r=x;i=y;
    }
    Complex operator +(const Complex &t)const{
        return Complex(r+t.r,i+t.i);
    }
    Complex operator -(const Complex &t)const{
        return Complex(r-t.r,i-t.i);
    }
    Complex operator *(const Complex &t)const{
        return Complex(r*t.r-i*t.i,r*t.i+i*t.r);
    }
}x1[5000100],x2[5000100];
void fft(Complex y[],int n,int rev)
{
    for(int i=1,j,k,t;i<n;i++){
       for(j=0,k=n>>1,t=i;k;k>>=1,t>>=1) j=j<<1|t&1;  //二进制位置互换
       if(i<j) swap(y[i],y[j]);
    }
    for(int s=2,ds=1;s<=n;ds=s,s<<=1){  //控制层数
      Complex wn=Complex(cos(rev*2*pi/s),sin(rev*2*pi/s)),w=Complex(1,0),t; //初始化单位复根和螺旋因子
      for(int k=0;k<ds;k++,w=w*wn){  //更新螺旋因子
         for(int i=k;i<n;i+=s){
             t=w*y[i+ds];        //蝴蝶操作
             y[i+ds]=y[i]-t;
             y[i]=y[i]+t;
         }
      }
    }
    if(rev==-1) for(int i=0;i<n;i++) y[i].r/=n;  //求逆
}
int main()
{
    int i,j,k,t;
    while(scanf("%s%s",str1,str2)!=EOF)
    {
        len1=strlen(str1);
        len2=strlen(str2);
        n=1;
        while(n<len1+len2) n<<=1;  
        for(i=0;i<len1;i++) x1[i]=Complex(str1[len1-i-1]-0,0);
        for(;i<n;i++) x1[i]=Complex(0,0);
        for(i=0;i<len2;i++) x2[i]=Complex(str2[len2-i-1]-0,0);
        for(;i<n;i++) x2[i]=Complex(0,0); //长度扩展
        fft(x1,n,1);
        fft(x2,n,1);   //系数表达式转点值表达式
        for(i=0;i<n;i++) x1[i]=x1[i]*x2[i]; //点值运算
        fft(x1,n,-1);  //求插值
        for(i=0,t=0;i<n;i++,t/=10){ //结果处理
            t+=(int)(x1[i].r+0.1); 
            num[i]=t%10;
        }
        for(;t;t/=10) num[i]=t%10;
        while(n>1&&!num[n-1]) n--;
        for(i=n-1;i>=0;i--) printf("%d",num[i]);
        printf("\n");
    }
    return 0;
}

 

HDU 1402 A * B Problem Plus(快速傅里叶变换)

标签:

原文地址:http://www.cnblogs.com/dominating/p/4661273.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!