FFT初次学习

转载:https://blog.csdn.net/xienaoban/article/details/69486299

说明:记录一下别人写的,将来忘了,可以回来看一下

卷积

给定向量:a=(a0,a1,…,an−1),b=(b0,b1,…,bn−1)
向量和:a+b=(a0+b0,a1+b1,…,an−1+bn−1)
数量积(内积、点积):a⋅b=a0b0+a1b1+…+an−1bn−1
卷积:a⊗b=(c0,c1,…,c2n−2),其中ck=∑i+j=k(aibj)
例如:cn−1=a0bn−1+a1bn−2+…+an−2b1+an−1b0
卷积的最典型的应用就是多项式乘法(多项式乘法就是求卷积)。以下就用多项式乘法来描述、举例卷积与DFT。

关于多项式

对于多项式A(x),系数为ai,设最高非零系数为ak,则其次数就是k,记作degree(A)=k。任何大于k的整数都是A(x)的次数界。

多项式的系数表达方式:A(x)=a0+a1x+a2x2+…+an−1xn−1=∑n−1i=0ajxj(次数界为n)。
则多项式的系数向量即为a=(a0,a1,…,an−1)。
多项式的点值表达方式:{(x0,y0),(x1,y1),…,(xn−1,yn−1)},其中xk各不相同,yk=A(xk)。

离散傅里叶变换(DFT)

离散傅里叶变换(Discrete Fourier Transform,DFT)。在信号处理很重要的一个东西,这里物理意义以及其他应用暂不予理睬。在多项式中,DFT就是系数表式转换成点值表示的过程。

快速傅里叶变换(FFT)

快速傅里叶变换(Fast Fourier Transformation,FFT):快速计算DFT的算法,能够在O(nlogn)的时间里完成DFT。FFT只是快速的求DFT的方法罢了,不是一个新的概念。 在ACM-ICPC竞赛中, FFT算法常被用来为多项式乘法加速。FFT与其逆变换IFFT类似,稍微加几行代码。

模板:

const double PI = acos(-1.0);
struct Complex {
    double x, y;
    Complex(double _x = 0.0, double _y = 0.0) {
        x = _x;
        y = _y;
    }
    Complex operator - (const Complex &b)const {
        return Complex(x-b.x, y-b.y);
    }
    Complex operator + (const Complex &b)const {
        return Complex(x+b.x, y+b.y);
    }
    Complex operator * (const Complex &b)const {
        return Complex(x*b.x-y*b.y, x*b.y+y*b.x);
    }
};

void change(Complex y[], int len) {
    int i, j, k;
    for(i = 1, j = len/2; i < len-1; i++) {
        if (i < j) swap(y[i], y[j]);
        k = len/2;
        while(j >= k) {
            j -= k;
            k /= 2;
        }
        if (j < k) j += k;
    }
}

void fft(Complex y[], int len, int on) {
    change(y, len);
    for(int h = 2; h <= len; h <<= 1) {
        Complex wn(cos(-on*2*PI/h), sin(-on*2*PI/h));
        for(int j = 0; j < len; j += h) {
            Complex w(1, 0);
            for(int k = j; k < j+h/2; k++) {
                Complex u = y[k];
                Complex t = w*y[k+h/2];
                y[k] = u+t;
                y[k+h/2] = u-t;
                w = w*wn;
            }
        }
    }
    if (on == -1)
        for(int i = 0; i < len; i++)
        y[i].x /= len;
}

这里写图片描述

fft(x1, len, 1);
fft(x2, len, 1);
for (int i = 0;i < len;i++) {
    x[i] = x1[i] * x2[i];
}
fft(x, len, -1);

接下来是例题:
转载:https://blog.csdn.net/qq_34494458/article/details/72764063

1、hdu1042

A * B Problem Plus
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 26267 Accepted Submission(s): 6821

Problem Description
Calculate A * B.

Input
Each line will contain two integers A and B. Process to end of file.

Note: the length of each integer will not exceed 50000.

Output
For each case, output A * B in one line.

Sample Input
1
2
1000
2

Sample Output
2
2000

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int N = 50002;

// 这一大坨fft的代码实现不要动的
const double PI = acos(-1.0);
struct Complex {
    double x, y;
    Complex(double _x = 0.0, double _y = 0.0) {
        x = _x;
        y = _y;
    }
    Complex operator - (const Complex &b)const {
        return Complex(x-b.x, y-b.y);
    }
    Complex operator + (const Complex &b)const {
        return Complex(x+b.x, y+b.y);
    }
    Complex operator * (const Complex &b)const {
        return Complex(x*b.x-y*b.y, x*b.y+y*b.x);
    }
};

void change(Complex y[], int len) {
    int i, j, k;
    for(i = 1, j = len/2; i < len-1; i++) {
        if (i < j) swap(y[i], y[j]);
        k = len/2;
        while(j >= k) {
            j -= k;
            k /= 2;
        }
        if (j < k) j += k;
    }
}

void fft(Complex y[], int len, int on) {
    change(y, len);
    for(int h = 2; h <= len; h <<= 1) {
        Complex wn(cos(-on*2*PI/h), sin(-on*2*PI/h));
        for(int j = 0; j < len; j += h) {
            Complex w(1, 0);
            for(int k = j; k < j+h/2; k++) {
                Complex u = y[k];
                Complex t = w*y[k+h/2];
                y[k] = u+t;
                y[k+h/2] = u-t;
                w = w*wn;
            }
        }
    }
    if (on == -1)
        for(int i = 0; i < len; i++)
        y[i].x /= len;
}
//数组要开四倍,2n长度然后乘起来就变成4n长度的了
LL num[N << 2];
char s1[N],s2[N];
Complex f1[N << 2],f2[N << 2];

int main()
{
    while(~scanf("%s %s",s1,s2))
    {
        int len1 = strlen(s1);
        int len2 = strlen(s2);
        int len = 1;
        while(len < 2 * len1 || len < 2 * len2) len <<= 1;
        //printf("%d %d %d\n",len1,len2,len);
        for(int i = 0;i < len1;++i)
        {
            f1[i] = Complex(s1[len1 - i - 1] - '0',0);
        }
        for(int i = len1;i < len;++i)
        {
            f1[i] = Complex(0,0);
        }
        fft(f1,len,1);
        for(int i = 0;i < len2;++i)
        {
            f2[i] = Complex(s2[len2 - i - 1] - '0',0);
        }
        for(int i = len2;i < len;++i)
        {
            f2[i] = Complex(0,0);
        }
        fft(f2,len,1);
        for(int i = 0;i < len;++i)
        {
            f1[i] = f1[i] * f2[i];
        }
        fft(f1,len,-1);
        for(int i = 0; i < len;++i)
        {
            num[i] = (LL)(f1[i].x + 0.5);
        }
        //处理进位
        for(int i = 0;i < len;++i)
        {
            num[i + 1] += num[i] / 10;
            num[i] = num[i] % 10;
        }
        len = len1 + len2 - 1;
        //去除多余0
        while(num[len] <= 0 && len > 0) len--;
        //printf("%d\n",len);
        for(int i = len;i >= 0;--i)
        {
            printf("%lld",num[i]);
        }
        printf("\n");
    }
    return 0;
}

2、hdu4609

3-idiots
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7590 Accepted Submission(s): 2643

Problem Description
King OMeGa catched three men who had been streaking in the street. Looking as idiots though, the three men insisted that it was a kind of performance art, and begged the king to free them. Out of hatred to the real idiots, the king wanted to check if they were lying. The three men were sent to the king’s forest, and each of them was asked to pick a branch one after another. If the three branches they bring back can form a triangle, their math ability would save them. Otherwise, they would be sent into jail.
However, the three men were exactly idiots, and what they would do is only to pick the branches randomly. Certainly, they couldn’t pick the same branch - but the one with the same length as another is available. Given the lengths of all branches in the forest, determine the probability that they would be saved.

Input
An integer T(T≤100) will exist in the first line of input, indicating the number of test cases.
Each test case begins with the number of branches N(3≤N≤105).
The following line contains N integers a_i (1≤a_i≤105), which denotes the length of each branch, respectively.

Output
Output the probability that their branches can form a triangle, in accuracy of 7 decimal places.

Sample Input
2
4
1 3 3 4
4
2 3 3 4

Sample Output
0.5000000
1.0000000

这篇博客讲的挺好
http://www.cnblogs.com/kuangbin/archive/2013/07/24/3210565.html

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int N = 100005;

// 这一大坨fft的代码实现不要动的
const double PI = acos(-1.0);
struct Complex {
    double x, y;
    Complex(double _x = 0.0, double _y = 0.0) {
        x = _x;
        y = _y;
    }
    Complex operator - (const Complex &b)const {
        return Complex(x-b.x, y-b.y);
    }
    Complex operator + (const Complex &b)const {
        return Complex(x+b.x, y+b.y);
    }
    Complex operator * (const Complex &b)const {
        return Complex(x*b.x-y*b.y, x*b.y+y*b.x);
    }
};

void change(Complex y[], int len) {
    int i, j, k;
    for(i = 1, j = len/2; i < len-1; i++) {
        if (i < j) swap(y[i], y[j]);
        k = len/2;
        while(j >= k) {
            j -= k;
            k /= 2;
        }
        if (j < k) j += k;
    }
}

void fft(Complex y[], int len, int on) {
    change(y, len);
    for(int h = 2; h <= len; h <<= 1) {
        Complex wn(cos(-on*2*PI/h), sin(-on*2*PI/h));
        for(int j = 0; j < len; j += h) {
            Complex w(1, 0);
            for(int k = j; k < j+h/2; k++) {
                Complex u = y[k];
                Complex t = w*y[k+h/2];
                y[k] = u+t;
                y[k+h/2] = u-t;
                w = w*wn;
            }
        }
    }
    if (on == -1)
        for(int i = 0; i < len; i++)
        y[i].x /= len;
}

int a[N];
Complex f1[N << 2];
LL num[N << 2];
LL sum[N << 2];

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        memset(num,0,sizeof(num));
        for(int i = 0;i < n;++i)
        {
            scanf("%d",&a[i]);
            num[a[i]]++;
        }
        sort(a,a + n);
        int len1 = a[n - 1] + 1;
        int len = 1;
        while(len < 2 * len1) len <<= 1;
        for(int i = 0;i < len1;++i)
        {
            f1[i] = Complex(num[i],0);
        }
        for(int i = len1;i < len;++i)
        {
            f1[i] = Complex(0,0);
        }
        fft(f1,len,1);
        for(int i = 0;i < len;++i)
        {
            f1[i] = f1[i] * f1[i];
        }
        fft(f1,len,-1);
        for(int i = 0;i < len;++i)
        {
            num[i] = (LL)(f1[i].x + 0.5);
        }
        len = 2 * a[n - 1];
        //减去两个相同的组合
        for(int i = 0;i < n;++i)
        {
            num[a[i] + a[i]]--;
        }
        //选择是无序的,要除以2,a,b和b,a是一种
        for(int i = 1;i <= len;++i)
        {
            num[i] /= 2;
        }
        //处理前缀和    
        sum[0] = 0;
        for(int i = 1;i <= len;++i)
        {
            sum[i] = sum[i - 1] + num[i];
        }
        LL cnt = 0;
        for(int i = 0;i < n;++i)
        {
            //依次筛选把a[i]作为三角形的最长边,需要减去一些不符合的和大于a[i]的情况
            cnt += sum[len] - sum[a[i]];
            //减掉一个取大,一个取小的
            cnt -= (LL)(n - i - 1) * i;
            //减掉一个取本身,另外一个取其它
            cnt -= (n - 1);
            //减掉大于它的取两个的组合
            cnt -= (LL)(n - i - 1) * (n - i - 2) / 2;
        }
        //总共有多少种取法,从n个中取三个
        LL tot = (LL)n * (n - 1) * (n - 2) / 6;
        printf("%.7lf\n",cnt / (tot * 1.0));
    }
    return 0;
}

更详细解释:https://blog.csdn.net/GGN_2015/article/details/68922404

猜你喜欢

转载自blog.csdn.net/qq_36386435/article/details/81610553
FFT