zoukankan      html  css  js  c++  java
  • P3338 [ZJOI2014]力(FFT)

    题目

    P3338 [ZJOI2014]力

    做法

    普通卷积形式为:(c_k=sumlimits_{i=1}^ka_ib_{k-i})
    其实一般我们都是用(i=0)开始的,但这题比较特殊,忽略那部分,其他的直接按下标存下来,反正最后的答案是不变的

    好了步入正题吧,我们定义 $$F_j=sumlimits_{i<j}dfrac{q_iq_j}{(i-j)^2}-sumlimits_{i<j}dfrac{q_iq_j}{(i-j)^2}$$

    (E_i=dfrac{F_i}{q_i})

    显然$$E_j=sumlimits_{i<j}dfrac{q_i}{(i-j)^2}-sumlimits_{i<j}dfrac{q_i}{(i-j)^2}$$

    [E_j=sum_{i=1}^{j-1}dfrac{q_i}{(i-j)^2}-sum_{i=j+1}^{n}dfrac{q_i}{(i-j)^2} ]

    (f_i=q_i,g_i=dfrac{1}{i^2}),特别地,(g_0=0),则有:$$E_j=sum_{i=1}^{j-1}f_ig_{i-j}-sum_{i=j+1}^{n}f_ig_{i-j}$$

    左边部分很简单就能化成卷积形式:$$sum_{i=1}^{j-1}f_ig_{i-j}=sum_{i=1}^{j-1}f_ig_{j-i}=sum_{i=1}^{j}f_ig_{j-i}$$

    右边部分:$$sumlimits_{i=j+1}^{n}f_ig_{i-j}=sumlimits_{i=1}^{n-j}f_{i+j}g_{i}$$

    (p_i=f_{n-i}),则(p_{n-i-j}=f_{i+j}),则有:$$sumlimits_{i=1}^{n-j}f_{i+j}g_{i}=sum_{i=1}^{n-j} p_{n-i-j}g_i$$

    都化成卷积形式了直接FFT

    My complete code

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const double Pi=acos(-1.0);
    const int maxn=300000;
    struct complex{
        double x,y;
        complex (double xx=0,double yy=0){
            x=xx,y=yy;
        }
    }f[maxn],p[maxn],g[maxn];
    int n,limit,L;
    int r[maxn];
    complex operator + (complex x,complex y){
        return complex(x.x+y.x,x.y+y.y);
    }
    complex operator - (complex x,complex y){
        return complex(x.x-y.x,x.y-y.y);
    }
    complex operator * (complex x,complex y){
        return complex(x.x*y.x-x.y*y.y,x.x*y.y+x.y*y.x);
    }
    inline void FFT(complex *A,int type){
        for(int i=0;i<limit;++i)
            if(i<r[i]) 
                swap(A[i],A[r[i]]);
        for(int mid=1;mid<limit;mid<<=1){
            complex WN(cos(Pi/mid),type*sin(Pi/mid));
            for(int R=mid<<1,j=0;j<limit;j+=R){
                complex w(1,0);
                for(int k=0;k<mid;++k,w=w*WN){
                    complex x=A[j+k],y=w*A[j+mid+k];
                    A[j+k]=x+y,
                    A[j+mid+k]=x-y;
                }
            }
        }
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            scanf("%lf",&f[i].x),f[i].y=0,
            g[i].x=(double)1.0/i/i;
            p[n-i].x=f[i].x;
        }
        limit=1,L=0;
        while(limit<n+n)
            limit<<=1,
            ++L;
        for(int i=0;i<limit;++i)
            r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
        FFT(f,1),FFT(p,1),FFT(g,1);
        for(int i=0;i<limit;++i)
            f[i]=f[i]*g[i];
        for(int i=0;i<limit;++i)
            p[i]=p[i]*g[i];
        FFT(f,-1),FFT(p,-1);
        for(int i=1;i<=n;++i)
            printf("%.3lf
    ",f[i].x/limit-p[n-i].x/limit);
        return 0;
    }/*
    */
    
  • 相关阅读:
    [你必须知道的.NET]第二十一回:认识全面的null
    《你必须知道的.NET》,内容简介
    [IT史记]开篇:盖茨本纪之离歌
    《你必须知道的.NET》,封面
    《博客园精华集》,CLR/C#分册征求意见稿
    [开发故事]第二回:LINQ来了,先忘记foreach
    《你必须知道的.NET》,封底
    [不得不转载]一个时代的结束:微软盖茨的人生掠影
    [技术速递]MSDN在线改版,新风格新体验
    《你必须知道的.NET》,勘误支持
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/10293217.html
Copyright © 2011-2022 走看看