zoukankan      html  css  js  c++  java
  • [ZJOI2014][bzoj3527]力 [FFT]

    题面

    传送门

    思路

    把要求的公式列出来:

    $E_i=frac{F_i}{q_i}=sum_{j=1}ifrac{q_j}{left(i-j ight)2}-sum_{j=i+1}nfrac{q_j}{left(i-j ight)2}$

    令$x_i=frac1{i^2}$,那么

    $E_i=sum_{j=1}iq_jx_{i-j}-sum_{j=i+1}nq_jx_{j-i}$

    那我们再令$p_i=q_{n-i+1}$,那么

    $E_i=sum_{j=1}iq_jx_{i-j}-sum_{j=i+1}np_{n-j}x_{j-i}$

    此时我们发现式子的左侧和右侧都是一个卷积的形式

    那么,我们就可以用FFT来维护这个过程了

    将数列$q_i$,$p_i$,$x_i$作为多项式$A$,$B$,$C$的系数

    将他们用fft乘起来,得到的$Aast C$,$Bast C$的系数做差,就是$E_i$的值

    Code:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    struct complex{
        double x,y;
        complex(double xx=0,double yy=0){x=xx;y=yy;}
        complex operator +(const complex &b){return complex(b.x+x,b.y+y);}
        complex operator -(const complex &b){return complex(-b.x+x,-b.y+y);}
        complex operator *(const complex &b){return complex(x*b.x-y*b.y,x*b.y+y*b.x);}
    }A[410010],B[410010],C[410010];
    const double pi=acos(-1.0);
    int n,limit=1,cnt=0,r[410010];
    void fft(complex *a,double type){
        int i,mid,j,k,R;complex w,wn,x,y;
        for(i=0;i<limit;i++) if(i<r[i]) std::swap(a[i],a[r[i]]);
        for(mid=1;mid<limit;mid<<=1){
            wn=complex(cos(pi/mid),type*sin(pi/mid));
            for(R=mid<<1,j=0;j<limit;j+=R){
                w=complex(1,0);
                for(k=0;k<mid;k++,w=w*wn){
                    x=a[j+k];y=w*a[j+k+mid];
                    a[j+k]=x+y;
                    a[j+k+mid]=x-y;
                }
            }
        }
    }
    int main(){
        scanf("%d",&n);int i;
        for(i=1;i<=n;i++) scanf("%lf",&A[i].x),B[n+1-i].x=A[i].x;
        for(i=1;i<=n;i++) C[i].x=(1.0/double(i))/double(i);
        
        while(limit<=(n<<1)) limit<<=1,cnt++;
        for(i=0;i<limit;i++) r[i]=((r[i>>1]>>1)|((i&1)<<(cnt-1)));
        
        fft(A,1);fft(B,1);fft(C,1);
        for(i=0;i<=limit;i++) A[i]=A[i]*C[i],B[i]=B[i]*C[i];
        fft(A,-1);fft(B,-1);
        for(i=0;i<=limit;i++) A[i].x/=limit,B[i].x/=limit;
        
        for(i=1;i<=n;i++) printf("%.4lf
    ",-B[n+1-i].x+A[i].x);
    }
    
  • 相关阅读:
    CSS3新增文本属性
    CSS选择器
    【转】Java基础——面试题汇总
    【转】equals和==的区别
    【转】JRE和JDK的区别
    【转】深度学习常用的模型评估指标
    【转】使用Scanner输入字符串时next()和nextLine()区别
    JAVA操作ORACLE大对象
    ORACLE大对象存储
    iis是什么东西?
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/8830852.html
Copyright © 2011-2022 走看看