洛谷:[ZJOI2014]力(FFT)

本文深入探讨了快速傅立叶变换(FFT)算法在解决特定数学问题中的应用,包括复杂数运算、卷积计算及逆变换过程。通过具体实例,展示了如何使用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);
    }
}

 

### 关于 `gr::fft::fft_` 的定义 在 GNU Radio 中,FFT(快速傅里叶变换)功能由模块 `gnuradio.fft` 提供支持。具体到 C++ 层面,`gr::fft::fft_*` 类型的实现主要位于 GNU Radio 的底层库中,这些类封装了 FFT 运算的核心逻辑并提供了高效的接口。 以下是关于 `gr::fft::fft_` 定义的相关说明: #### 1. **核心类:`gr::fft::fft`** `gr::fft::fft` 是一个模板类,用于处理不同数据类型的 FFT 计算[^2]。它通常通过以下方式实例化: ```cpp template <class T> class fft { public: fft(int size, bool forward); ~fft(); void execute(const T* input, T* output) const; private: int d_size; // FFT 大小 bool d_forward; // 是否正向变换 }; ``` 此模板类中的参数解释如下: - `size`: 表示 FFT 变换的数据长度。 - `forward`: 布尔值,指示是否执行正向 (`true`) 或逆向 (`false`) FFT。 此类的具体实现在 GNU Radio 的源码目录下可以找到,路径通常是 `lib/fft.cc` 和头文件 `include/gnuradio/fft/fft.h`[^3]。 #### 2. **派生类与辅助工具** 除了基础的 `gr::fft::fft` 模板外,GNU Radio 还提供了一些特定用途的派生类和工具函数,例如: - `gr::fft::window`: 用于生成各种窗口函数 (如 Hamming、Hann),以便在频谱分析前应用窗函数减少泄漏效应[^4]。 - `gr::fft_vcc`: 针对复数输入信号的矢量 FFT 实现,适用于常见的通信场景。 其典型用法可能类似于下面的例子: ```cpp #include <gnuradio/fft/fft.h> int main() { gr::fft::fft<float> my_fft(1024, true); // 创建大小为 1024 的正向 FFT 对象 float input_data[1024], output_data[1024]; // 执行 FFT 转换 my_fft.execute(input_data, output_data); return 0; } ``` 上述代码展示了如何创建一个基于浮点数的 FFT 对象,并调用其方法完成实际计算[^5]。 #### 3. **Python 接口映射** 虽然您提到的是 Python 脚本环境下的使用案例,但在 Python 中访问低级 C++ API 并不常见。相反,GNU Radio 提供了一组经过优化的高层接口,比如 `numpy.fft` 或者专门设计好的 GRC 流图组件。如果确实需要深入研究底层机制,则可以通过 SWIG 绑定或者 Cython 来桥接 C++ 和 Python[^6]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值