• [BZOJ]3527 力(ZJOI2014)


      第一次背出FFT模板,在此mark一道裸题。

    Description

      给出n个数qi,给出Fj的定义如下:

      

      令Ei=Fi/qi,求Ei。

    Input

      第一行一个整数n。
      接下来n行每行输入一个数,第i行表示qi。

    Output

      n行,第i行输出Ei。与标准答案误差不超过1e-2即可。

    Sample Input

      5
      4006373.885184
      15375036.435759
      1717456.469144
      8514941.004912
      1410681.345880

    Sample Output

      -16838672.693
      3439.793
      7509018.566
      4595686.886
      10903040.872

    HINT

      n ≤ 100000,0 < qi < 1000000000。

    Solution

      看到题目中 下标为j的项等于下标为i的项与下标为j±i的项的乘积之和,你应该会有所感觉吧。

      设,那么 

      显然两边都是卷积的式子,所以两边分别做一次FFT就可以了。

      然而我们再思考一下,发现两边的式子是可以合并的:

      设,那么 就完全成立了。只要做一次FFT就够了。

      时间复杂度O(nlogn)。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #define pi acos(-1)
    #define MN 263005
    using namespace std;
    struct cp
    {
        double v,i;
        friend cp operator+(const cp& a,const cp& b) {return (cp){a.v+b.v,a.i+b.i};}
        friend cp operator-(const cp& a,const cp& b) {return (cp){a.v-b.v,a.i-b.i};}
        friend cp operator*(const cp& a,const cp& b) {return (cp){a.v*b.v-a.i*b.i,a.v*b.i+a.i*b.v};}
    }w[2][MN],A[MN],B[MN],C[MN];
    double a[MN];
    int r[MN];
    int N,n;
    
    void init(int n)
    {
        register int i,j,k;
        for (N=1;N<=n;N<<=1); cp g=(cp){cos(pi*2/N),sin(pi*2/N)};
        for (i=j=0;i<N;r[++i]=j)
            for (k=N>>1;(j^=k)<k;k>>=1);
        w[0][0]=w[1][0]=(cp){1,0};
        for (i=1;i<N;++i) w[0][i]=w[0][i-1]*g;
        for (i=1;i<N;++i) w[1][i]=w[0][N-i];
    }
    
    void FFT(cp* a,bool g)
    {
        register int i,j,k;
        for (i=1;i<N;++i) if (r[i]<i) swap(a[i],a[r[i]]);
        for (i=1;i<N;i<<=1)
            for (j=0;j<N;j+=(i<<1))
                for (k=0;k<i;++k)
                {
                    cp x=a[i+j+k]*w[g][N/(i<<1)*k];
                    a[i+j+k]=a[j+k]-x;
                    a[j+k]=a[j+k]+x;
                }
        if (g) for (i=0;i<N;++i) a[i].v/=N,a[i].i/=N;
    }
    
    int main()
    {
        register int i;
        scanf("%d",&n);
        for (i=1;i<=n;++i) scanf("%lf",&a[i]),A[i].v=a[i];
        for (i=1;i<n;++i)
            B[n+i].v=(double)1/i/i,B[n-i].v=(double)-1/i/i;
        init(n<<1);
        FFT(A,0); FFT(B,0);
        for (i=0;i<N;++i) C[i]=A[i]*B[i];
        FFT(C,1);
        for (i=1;i<=n;++i) printf("%.7lf
    ",C[n+i].v);
    }

    Last Word

      推荐miskcoo的关于学习FFT的blog:从多项式乘法到快速傅里叶变换

  • 相关阅读:
    关于extern的用法
    建立CMenu菜单项,实现选中菜单项点击左键响应事件
    数据库常用语句
    圆周率的计算
    C++11中list特有版本的算法
    使用istream迭代器来输入输出数据
    C++中函数重载和函数覆盖的区别
    外置接口请求
    JSON转指定复杂对象
    FastDFS优化
  • 原文地址:https://www.cnblogs.com/ACMLCZH/p/8214047.html
Copyright © 2020-2023  润新知