洛谷:[ZJOI2014]力(FFT)

点我查看题目

题目描述

给出n个数qi,给出Fj的定义如下:

F_j = \sum_{i<j}\frac{q_i q_j}{(i-j)^2 }-\sum_{i>j}\frac{q_i q_j}{(i-j)^2 }Fj​=∑i<j​(i−j)2qi​qj​​−∑i>j​(i−j)2qi​qj​​

令Ei=Fi/qi,求Ei.

输入输出格式

输入格式:

 

第一行一个整数n。

接下来n行每行输入一个数,第i行表示qi。

 

输出格式:

 

n行,第i行输出Ei。

与标准答案误差不超过1e-2即可。

 

输入输出样例

输入样例#1: 复制

5
4006373.885184
15375036.435759
1717456.469144
8514941.004912
1410681.345880

输出样例#1: 复制

-16838672.693
3439.793
7509018.566
4595686.886
10903040.872

说明

对于30%的数据,n≤1000。

对于50%的数据,n≤60000。

对于100%的数据,n≤100000,0<qi<1000000000。

[spj 0.01]

思路:预处理C[i] = 1/(i*i)之后就是求卷积,右半部分只需要将Q数组反转,就能用卷积解决,FFT。

# include <bits/stdc++.h>
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);
    for(int i=1; i<=n; ++i){
        scanf("%lf",&A[i].x);
        B[n-i+1].x = A[i].x;
        C[i].x = (1.0/(double)i)/(double)i;
    }
    while(limit<=(n<<1)) limit<<=1,cnt++;
    for(int 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(int i=0; i<=limit; ++i) A[i] = A[i]*C[i], B[i] = B[i]*C[i];
    fft(A,  -1);
    fft(B,  -1);
    for(int i=1; i<=n; ++i){
        double tmp = A[i].x/limit - B[n-i+1].x/limit;//整数要加0.5再取整
        printf("%.4f\n",tmp);
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值