• 洛谷 P3338 【ZJOI2014】力/BZOJ 3527 力 题解


    洛谷 P3338 【ZJOI2014】力/BZOJ 3527 力 题解

    题意

    给定一个正整数(n(1leq nleq 10^5)),以及有(n)个元素的浮点数序列(q(0<q_i<10^9)).要求对于所有的(iin [1,n]),输出

    [E_j=sum_{i=1}^{j-1}frac{q_i imes q_j}{(i-j)^2}-sum_{i=j+1}^nfrac{q_i imes q_j}{(i-j)^2} ]

    注:当你输出的答案与标准答案相差不超过(10^{-2})时,即视为答案正确.

    题解

    显然,暴力是行不通的,所以考虑使用(FFT)进行卷积来处理.
    首先考虑序列能进行卷积所要满足的条件:

    [c_i=sum_{j=0}^ia_j imes b_{n-j} ]

    所以我们必须要把原式变得好看一点才能进行卷积.
    我们不妨令(a_i=q_i,b_i=frac{1}{i^2}),那么可以对原式进行一下变形:

    [E_j=sum_{i=1}^{j-1}frac{q_i imes q_j}{(i-j)^2}-sum_{i=j+1}^nfrac{q_i imes q_j}{(i-j)^2} =sum_{i=1}^{j-1}a_ib_{j-i}-sum_{i=j+1}^{n}a_ib_{i-j} ]

    那么当我们令(a_0=b_0=0)时,不难发现将其变形为

    [sum_{i=0}^{j}a_ib_{j-i}-sum_{i=j}^{n}a_ib_{i-j} ]

    依然是正确的.此时前一项已经满足卷积的要求了,我们单独处理后一项.
    不难证明一下变形这正确的:

    [sum_{i=j}^{n}a_ib_{i-j}=sum_{i=0}^{n-j}a_{i+j}b_i ]

    接下来运用反转的思想,令(c_i=a_{n-i}),那么可变形为

    [sum_{i=0}^{n-j}a_{i+j}b_i=sum_{i=0}^{n-j}c_{n-i-j}b_i ]

    这样一来,第二个式子也满足卷积的条件啦!
    所以我们对(a)(b)跑一次(FFT),再对(b)(c)跑一次(FFT),设得到的两个序列为(p)(q),那么答案就为(E_j=p_j-q_{n-j}),套上(FFT)的板子即可.

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define M_PI 3.141592653589793
    typedef complex<long double> comp;
    const int MAXN=100010;
    const comp I(0,1);
    int n;
    comp a[MAXN*4];
    comp b[MAXN*4];
    inline void change(comp *f,int len)
    {
        for(int i=1,j=len>>1;i<len-1;i++)
        {
            if(i<j) swap(f[i],f[j]);
            int k=len>>1;
            while(j>=k)
            {
                j-=k;
                k>>=1;
            }
            if(j<k) j+=k;
        }
    }
    inline void FFT(comp *f,int len,int rev)
    {
        change(f,len);
        for(int h=2;h<=len;h<<=1)
        {
            comp wn=exp(I*(long double)(2*M_PI/h*rev));
            for(int i=0;i<len;i+=h)
            {
                comp cur(1,0);
                for(int j=i;j<i+(h>>1);j++)
                {
                    comp p=f[j],q=cur*f[j+(h>>1)];
                    f[j]=p+q,f[j+(h>>1)]=p-q;
                    cur*=wn;
                }
            }
        }
        if(rev==-1)
        for(int i=0;i<len;i++) f[i]/=len;
    }
    comp c[MAXN*4];
    int len;
    int main()
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            long double x;
            scanf("%Lf",&x);
            a[i]={x,0};
        }
        for(int i=1;i<n;i++) b[i]=1.0/(1.0*(long double)i*(long double)i);
        for(int i=0;i<n;i++) c[i]=a[n-i];
        len=1;
        while(len<=2*n) len<<=1;
        FFT(a,len,1),FFT(b,len,1),FFT(c,len,1);
        for(int i=0;i<len;i++) c[i]*=b[i],b[i]*=a[i];
        FFT(b,len,-1),FFT(c,len,-1);
        for(int i=0;i<n;i++) printf("%.3Lf
    ",real(b[i]-c[n-i]));
    	return 0;
    }
    

    后记

    本人第一次做(FFT)练习题,感觉还算顺利(除了悄悄地看了两眼题解的解题思路)比较惨的是之前π精度不够结果居然一片红,所有点都差零点几的样子QAQ所幸后面改过来之后一边就过了吧……最后我一定要吐槽一句,数学题的(LaTeX)真难写……搞了半天才搞定QAQ

  • 相关阅读:
    选择排序
    java面试题08
    java面试题07
    java面试题06
    java面试题05
    oop.1
    4
    3
    Struts1中actionform和action属于MVC哪一层
    mysql查询时间段的所有数据
  • 原文地址:https://www.cnblogs.com/xiaoh105/p/12323002.html
Copyright © 2020-2023  润新知