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);
    }
    
  • 相关阅读:
    文本中溢出的文字在结尾显示为三个点
    git bash 如何建分支
    git本地仓库和远程仓库连接
    button不能直接添加href属性实现页面跳转
    【JAVA】【集合9】ArrayList和Vector区别
    【JAVA】【集合8】Java中的Vector
    【JAVA】【集合7】Java中的ArrayList
    【JAVA】【集合6】Java中的Collections工具类
    【JAVA】【集合5】Java中的List接口
    【JAVA】【集合4】Java中的Collection接口
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/8830852.html
Copyright © 2011-2022 走看看