P3338 [ZJOI2014]力

思路

颓柿子的题目

要求求这样的一个式子
\[
F_j=\sum_{i<j}\frac{q_iq_j}{(i-j)^2}-\sum_{i>j}\frac{q_iq_j}{(i-j)^2}
\]
令\(E_i=\frac{F_i}{q_i}\),求所有的\(E_i\)

对于Ei,显然可以
\[
E_i=\sum_{j=0}^{i-1}\frac{q_j}{(i-j)^2}-\sum_{j=i+1}^n\frac{q_j}{(i-j)^2}
\]
前后没什么关联,可以分开考虑,首先考虑前面部分
\[
\sum_{j=0}^{i-1}\frac{q_j}{(i-j)^2}
\]
设\(f(i)=q_i\),\(g(i)=\frac{1}{i^2}\)

则前面一部分变为
\[
\sum_{j=0}^{i-1}f(j)g(i-j)
\]
变成了卷积的形式

后面一部分是
\[
\sum_{j=i+1}^{n}\frac{q_j}{(i-j)^2}
\]
同理变成
\[
\sum_{j=i+1}^nf(j)g(j-i)
\]
似乎没什么办法,但是我们可以把\(f\)整个反过来(就是\(f(1)\)与\(f(n)\)交换,与\(f(2)\)与\(f(n-1)\)交换)

设交换之后的\(f\)为\(f'\),\(f'_i=f_{n-i+1}\)

则有
\[
\sum_{j=0}^{i-1}f'(j)g(j-i)
\]
则原来的第i项和反转后的第\(n-i+1\)项相同

对应相减即可

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define int long long
using namespace std;
const double pi = acos(-1.0);
struct complex{//a+bi
    double a,b;
    complex operator + (complex &bx){
        return (complex){a+bx.a,b+bx.b};
    }
    complex operator - (complex &bx){
        return (complex){a-bx.a,b-bx.b};
    }
    complex operator * (complex &bx){
        return (complex){a*bx.a-b*bx.b,b*bx.a+a*bx.b};
    }
    complex conj(void){
        return (complex){a,-b};
    }
};
int n;
double q[401000],ans[401000];
complex inv[401000],wnk[401000],a[401000],b[401000];
void init(int len){
    for(int i=0;i<len;i++){
        wnk[i]=(complex){cos(2*pi*i/len),sin(2*pi*i/len)};
        inv[i]=wnk[i].conj();
    }
}
void FFT(complex *a,complex *opt,int n){
    int lim=0;
    while((1<<lim)<n){
        lim++;
    }
    n=(1<<lim);
    for(int i=0;i<n;i++){
        int t=0;
        for(int j=0;j<lim;j++)
            if((i>>j)&1)
                t|=(1<<(lim-j-1));
        if(t<i)
            swap(a[i],a[t]);
    }
    for(int i=2;i<=n;i<<=1){
        int len=i/2;
        for(complex *j=a;j!=a+n;j+=i){
            for(int k=0;k<len;k++){
                complex t=j[k+len]*opt[n/i*k];
                j[k+len]=j[k]-t;
                j[k]=j[k]+t;
            }
        }
    }
}
void Do_FFT(int n){
    int lim=0;
    while((1<<lim)<n){
        lim++;
    }
    n=(1<<lim);
    init(n);
    FFT(a,wnk,n);
    FFT(b,wnk,n);
    for(int i=0;i<n;i++)
        a[i]=a[i]*b[i];
    FFT(a,inv,n);
    for(int i=0;i<n;i++)
        a[i].a/=n;
}
signed main(){
    // freopen("1.in","r",stdin);
    // freopen("test.out","w",stdout);
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){
        scanf("%lf",&q[i]);
    }
    for(int i=1;i<=n;i++){
        a[i].a=q[i];
        b[i].a=1.0/(i*i);
        a[i].b=0;
        b[i].b=0;
    }
    Do_FFT(2*n+4);
    for(int i=1;i<=n;i++)
        ans[i]=a[i].a;
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    for(int i=1;i<=n;i++){
        a[i].a=q[i];
        b[i].a=1.0/(i*i);
        a[i].b=0;
        b[i].b=0;
    }
    for(int i=1,j=n;i<j;i++,j--)
        swap(a[i],a[j]);
    Do_FFT(2*n+4);
    for(int i=1;i<=n;i++)
        ans[i]-=a[n-i+1].a;
    for(int i=1;i<=n;i++)
        printf("%.3lf\n",ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/dreagonm/p/10559235.html

时间: 2025-01-11 10:19:08

P3338 [ZJOI2014]力的相关文章

P3338 [ZJOI2014]力 /// FFT 公式转化翻转

题目大意: https://www.luogu.org/problemnew/show/P3338 题解 #include <bits/stdc++.h> #define N 300005 #define PI acos(-1.0) using namespace std; struct cpx { double x,y; cpx (double a=0.0,double b=0.0) { x=a; y=b; } cpx operator - (const cpx &b)const {

[bzoj3527] [洛谷P3338] [Zjoi2014]力

Description 给出n个数qi,给出Fj的定义如下: \[ F_j=\sum\limits_{i<j} \frac{q_iq_j}{(i-j)^2} - \sum\limits_{i>j} \frac{q_iq_j}{(i-1)^2} \] 令Ei=Fi/qi,求Ei. Input 第一行一个整数n. 接下来n行每行输入一个数,第i行表示qi. n≤100000,0<qi<1000000000 Output n行,第i行输出Ei.与标准答案误差不超过1e-2即可. Samp

luogu P3338 [ZJOI2014]力 |FFT

我是机房最后一个学会fft的菜鸡.. 推柿子,套模板 找找bug,乱搞一下 #include<cmath> #include<cstdio> #include<complex> #include<iostream> #include<algorithm> using namespace std; #define ll long long const int N = 4e5+10; const double pi=acos(-1.0); typed

BZOJ 3527: [Zjoi2014]力 [快速傅里叶变换]

3527: [Zjoi2014]力 Time Limit: 30 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 1723  Solved: 1015[Submit][Status][Discuss] Description 给出n个数qi,给出Fj的定义如下: 令Ei=Fi/qi,求Ei. Input 第一行一个整数n. 接下来n行每行输入一个数,第i行表示qi. n≤100000,0<qi<1000000000 Output n行,第i

[Zjoi2014]力 FFT

#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> using namespace std; typedef double dd; const dd pi=acos(0.0)*2; #define N 400005 struct P{ dd x,y; P(dd A=0.0,dd B=0.0){ x=A; y=B; } P

【BZOJ 3527】 [Zjoi2014]力

3527: [Zjoi2014]力 Description 给出n个数qi,给出Fj的定义如下: 令Ei=Fi/qi,求Ei. Input 第一行一个整数n. 接下来n行每行输入一个数,第i行表示qi. Output n行,第i行输出Ei. 与标准答案误差不超过1e-2即可. Sample Input 5 4006373.885184 15375036.435759 1717456.469144 8514941.004912 1410681.345880 Sample Output -16838

BZOJ 3527: [Zjoi2014]力 FFT

3527: [Zjoi2014]力 Description 给出n个数qi,给出Fj的定义如下: 令Ei=Fi/qi,求Ei. Input 第一行一个整数n. 接下来n行每行输入一个数,第i行表示qi. n≤100000,0<qi<1000000000 Output n行,第i行输出Ei.与标准答案误差不超过1e-2即可. Sample Input 5 4006373.885184 15375036.435759 1717456.469144 8514941.004912 1410681.34

3527: [Zjoi2014]力 - BZOJ

题目大意:给出n个数qi,定义 Fj为 令 Ei=Fi/qi,求Ei. 看了很久题解,终于有些眉目,因为知道要用FFT,所以思路就很直了 其实我们就是要±1/(j-i)^2 ( i-j大于0时为正,小于0时为负 ) 和 qi 的乘积要算到j这个位置上,这个满足卷积,所以用FFT优化,但是j-i有负数,所以我们就加上一个n 于是设pi={ i>n,1/(i-n)^2 i<n,-1/(n-i)^2 其他,0 } 然后就套FFT模板就行了 1 const 2 maxn=800100; 3 type

BZOJ[3527],[ZJOI2014]力(FFT)

BZOJ[3527],[ZJOI2014]力(FFT) 题意: 给出\(n\)个数\(q_i\),给出\(Fj\)的定义如下: \(F_j=\sum \limits _ {i < j} \frac{q_iq_j}{(i-j)^2}-\sum \limits _{i >j} \frac{q_iq_j}{(i-j)^2}.\) 令\(E_i=F_i/q_i\),求\(E_i\). 题解: 一开始没发现求\(E_i\)... 其实题目还更容易想了... \(E_i=\sum\limits _{j&l