BZOJ 3527 【ZJOI2014】 力

题目链接:

  听说这道题是(FFT)板子题,于是我就来写了……

  首先可以发现这个式子:[E_i=sum_{j<i}frac{q_j}{(i-j)^2}-sum_{j>i}frac{q_j}{(i-j)^2} ]

  然后可以对两半分别考虑一下。发现下标刚好是(j+(i-j)=i),于是我们就可以开始构(gao)造(shi)了,弄俩多项式出来:

[A_1(x)=0x^0+q_1x^1+q_2x^2+dots+q_nx^n]

[A_2(x)=frac{-1}{n^2}x^0+frac{-1}{(n-1)^2}x^1+dots+0x^n+dots+frac{1}{(n-1)^2}x^{2n-1}+frac{1}{n^2}x^{2n}]

  把这两个多项式乘起来,取次数为((n,2n])的项前面的系数即为答案。

  实际上,把多函数(A_1(x))的系数全部左移一位也是可以的,只不过答案的区间要跟着移一下。

  下面贴代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<complex>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define C complex<double>
#define maxn 300010
#define pi (acos(-1))
  
using namespace std;
typedef double llg;
  
int n,m,L,R[maxn];
C a[maxn],b[maxn];
 
llg gi(int x){return 1.0*x*x;}
void fft(C *a){
    for(int i=0;i<n;i++) if(i<R[i]) swap(a[i],a[R[i]]);
    for(int i=1;i<n;i<<=1){
        C wn(cos(pi/i),sin(pi/i)),x,y;
        for(int j=0;j<n;j+=(i<<1)){
            C w(1,0);
            for(int k=0;k<i;k++,w*=wn){
                x=a[j+k]; y=w*a[j+i+k];
                a[j+k]=x+y; a[j+i+k]=x-y;
            }
        }
    }
}
  
int main(){
    scanf("%d",&n); m=n;
    for(int i=0;i<n;i++) scanf("%lf",&a[i].real());
    for(int i=0;i<n;i++) b[i].real()=-1.0/gi(n-i),b[2*n-i]=-b[i];
    for(n=1;n<=(m<<1);n<<=1) L++;
    for(int i=0;i<n;i++) R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
    fft(a); fft(b);
    for(int i=0;i<n;i++) a[i]*=b[i];
    fft(a); reverse(a+1,a+n);
    for(int i=m;i<(m<<1);i++) printf("%.6lf
",a[i].real()/n);
    return 0;
}
 
原文地址:https://www.cnblogs.com/lcf-2000/p/6371720.html