zoukankan      html  css  js  c++  java
  • BZOJ 2179 FFT快速傅立叶 ——FFT

    【题目分析】

        快速傅里叶变换用于高精度乘法。

        其实本质就是循环卷积的计算,也就是多项式的乘法。

        两次蝴蝶变换。

        二进制取反化递归为迭代。

        单位根的巧妙取值,是的复杂度成为了nlogn

        范德蒙矩阵计算逆矩阵又减轻了拉格朗日插值法的复杂度。

        十分神奇。

    【代码】

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
     
    #include <set>
    #include <map>
    #include <string>
    #include <algorithm>
    #include <vector>
    #include <iostream>
    #include <queue>
     
    using namespace std;
     
    #define maxn 200005
    #define Complex cp
    #define F(i,j,k) for (int i=j;i<=k;++i)
    #define D(i,j,k) for (int i=j;i>=k;--i) 
    #define mlog 16
    #define inf (0x3f3f3f3f)
     
    int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();}
        while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
     
    struct cp{
        double x,y;//虚数可表示为 x+y*i  i^2=-1 
        cp operator + (cp a) {return (cp){x+a.x,y+a.y};}
        cp operator - (cp a) {return (cp){x-a.x,y-a.y};}
        cp operator * (cp a) {return (cp){x*a.x-y*a.y,x*a.y+y*a.x};}
    }a[maxn],b[maxn],c[maxn];
     
    double pi=acos(-1.0); // π 
    int n,m,rev[maxn],len,ans[maxn];
    char s[maxn];
    
    void FFT(Complex * x,int n,int f)
    {
    	F(i,0,n-1) if (rev[i]>i) swap(x[rev[i]],x[i]); //构造迭代的形式
    	for (int m=2;m<=n;m<<=1)
    	{
    		Complex wn=(Complex){cos(2.0*pi/m*f),sin(2.0*pi/m*f)}; //当前的主单位根
    		for (int i=0;i<n;i+=m)
    		{
    			Complex w=(Complex){1.0,0}; 
    			for (int j=0;j<(m>>1);++j)
    			{
    				Complex u=x[i+j],v=x[i+j+(m>>1)]*w;//计算对应的多项式的值 
    				x[i+j]=u+v; x[i+j+(m>>1)]=u-v;
    				w=w*wn;//在复数域中旋转一个角度 
    			}
    		}
    	}
    } 
     
    int main()
    {
        n=read();
        scanf("%s",s); F(i,0,n-1) a[i].x=s[n-1-i]-'0';
        scanf("%s",s); F(i,0,n-1) b[i].x=s[n-1-i]-'0';
        m=1; n=2*n-1;
        while (m<=n) m<<=1,len++; n=m;
        F(i,0,n-1)
        {
            int t=i,ret=0;
            F(j,1,len) ret<<=1,ret|=t&1,t>>=1;
            rev[i]=ret;
        }//二进制翻转,便于化分治为循环迭代 
        FFT(a,n,1); FFT(b,n,1); //FFT 
        F(i,0,n-1) c[i]=a[i]*b[i];
        FFT(c,n,-1); //IFFT
        F(i,0,n-1) ans[i]=(c[i].x/n)+0.5;//精度QAQ 
        F(i,0,n-1) ans[i+1]+=ans[i]/10,ans[i]%=10;//进位QwQ 
        n++;
        while (!ans[n]&&n) n--;
        D(i,n,0) printf("%d",ans[i]);
    }
    

      

  • 相关阅读:
    SQL中char,varchar,nvarchar等的异同
    SQL中group by的用法
    如何管理自己的时间
    ref和out
    SQL中的日期时间函数
    SQL中的类型转换
    SQL中的自定义函数Function
    SQL中的模糊查询
    Struct是干什么的
    把普通图片转换成二进制
  • 原文地址:https://www.cnblogs.com/SfailSth/p/6352125.html
Copyright © 2011-2022 走看看