快速傅里叶变换(fft + 例题 Gym100783C)

快速傅里叶变换 (fast Fourier transform), 即利用计算机计算离散傅里叶变换(DFT)的高效、快速计算方法的统称,简称FFT。快速傅里叶变换是1965年由J.W.库利和T.W.图基提出的。采用这种算法能使计算机计算离散傅里叶变换所需要的乘法次数大为减少,特别是被变换的抽样点数N越多,FFT算法计算量的节省就越显著。
具体的贴出学习资源,个人认为讲解的非常好。
https://blog.csdn.net/ggn_2015/article/details/68922404
click
click
知识点以及证明综合都有利于理解。

上一道例题Gym100783C
题意:给定n个数的数组a,m个数的数组b,问b数组中的数有多少个可以由a数组中的1或者2个数值和组成,可以重复在a数组中选取。

可以看成,两个多项式的相乘,指数级别是相加的,系数分存在或者不存在,即0或者1。即a数组*a数组,看最后中的指数部分是否在b中出现。

自己非常菜,改的板子。

#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 210*4
using namespace std;
typedef long long ll;
const int MAXN = 262144 * 2+ 10;
const double PI = std::acos(-1.0);

struct Complex {
    double r, i;

    Complex(double r = 0, double i = 0) : r(r), i(i) {}

    Complex conj() const { return Complex(r, -i); }

    Complex operator+(const Complex &rhs) const { return Complex(r + rhs.r, i + rhs.i); }
    Complex operator-(const Complex &rhs) const { return Complex(r - rhs.r, i - rhs.i); }
    Complex operator*(const Complex &rhs) const { return Complex(r * rhs.r - i * rhs.i, r * rhs.i + i * rhs.r); }
    Complex operator/(double rhs) const { return Complex(r / rhs, i / rhs); }
};

class FFT {
private:
    static const int N = 262144*2;

    Complex omega[N + 1], omegaInv[N + 1];

    void init() {
        for (int i = 0; i < N; i++) {
            omega[i] = Complex(std::cos(2 * PI / N * i), std::sin(2 * PI / N * i));
            omegaInv[i] = omega[i].conj();
        }
    }

    void reverse(Complex *a, int n) {
        for (int i = 0, j = 0; i < n; i++) {
            if (i < j) std::swap(a[i], a[j]);
            for (int l = n >> 1; (j ^= l) < l; l >>= 1) {}
        }
    }

    void transform(Complex *a, int n, Complex *omega) {
        reverse(a, n);

        for (int l = 2; l <= n; l <<= 1) {
            int hl = l >> 1;
            for (Complex *x = a; x != a + n; x += l) {
                for (int i = 0; i < hl; i++) {
                    Complex t = omega[N / l * i] * x[i + hl];
                    x[i + hl] = x[i] - t;
                    x[i] = x[i] + t;
                }
            }
        }
    }

public:
    FFT() { init(); }

    int extend(int n) {
        int res = 1;
        while (res < n) res <<= 1;
        return res;
    }

    void dft(Complex *a, int n) {
        transform(a, n, omega);
    }

    void idft(Complex *a, int n) {
        transform(a, n, omegaInv);
        for (int i = 0; i < n; i++) a[i] = a[i] / n;
    }
} fft;
int aaa[MAXN];
map<int,int>hh1;
int main() {
    int n, m;
    scanf("%d", &n);

    static Complex a[MAXN], b[MAXN];
    int MAXXX=0;
    for(int i=0;i<n;i++)
    {
        scanf("%d",&aaa[i]);
        hh1[aaa[i]]=1;
        MAXXX=max(MAXXX,aaa[i]);
    }
    for (int i = 0, x; i <=MAXXX; i++) {
        if(hh1[i])
        a[i] = Complex(1, 0);
        else
             a[i] = Complex(0, 0);
    }

    for (int i = 0; i <=MAXXX; i++) {
        if(hh1[i])
        a[i] = a[i] + Complex(0,1);
        else
                    a[i] = a[i] + Complex(0,0);
    }

    int len =MAXXX + MAXXX + 1;
    int N = fft.extend(len);

    fft.dft(a, N);
    for (int i = 1; i < N; i++) {
        double x1 = a[i].r, y1 = a[i].i;
        double x2 = a[N - i].r, y2 = a[N - i].i;
        Complex t1((x1 + x2) * 0.5, (y1 - y2) * 0.5);
        Complex t2((y1 + y2) * 0.5, (x2 - x1) * 0.5);
        b[i] = t1 * t2;
    }
    b[0] = a[0].r * a[0].i;
    fft.idft(b, N);
    int ans=0;
    for (int i = 0; i < len; i++)
    {
        int temp=(round(b[i].r));
        if(temp)
        {
            hh1[i]=1;
        }
    }
    scanf("%d",&m);
    for(int i=0;i<m;i++)
    {
        int x;
        scanf("%d",&x);
        if(hh1[x])
            ans++;
    }
     printf("%d",ans);

    return 0;
}
/*
3
1 3 5
6
2 4 5 7 8 9
*/

猜你喜欢

转载自blog.csdn.net/weixin_43958964/article/details/106175487