zoukankan      html  css  js  c++  java
  • FFT快速傅里叶变换

    摘自:https://www.cnblogs.com/RabbitHu/p/FFT.html

    快速傅里叶变换(FFT): 一种能在O(nlogn)的时间内将一个多项式转换成它的点值表示的算法。

    点值表示:设A(x)是一个n−1次多项式,那么把n个不同的x代入,会得到n个y。这n对(x,y)唯一确定了该多项。由多项式可以求出其点值表示,而由点值表示也可以求出多项式。

    设有两个n−1次多项式A(x)和B(x)),我们的目标是——把它们乘起来。普通的多项式乘法是O(n^2),但有趣的是,两个用点值表示的多项式相乘,复杂度是O(n)的!具体方法:C(xi)=A(xi)×B(xi)。


    高精度乘法:等价于x=10的A(x)*B(x)

     1 #include <cstdio>
     2 #include <cmath>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <complex>
     6 #define space putchar(' ')
     7 #define enter putchar('
    ')
     8 using namespace std;
     9 typedef long long ll;
    10 template <class T>
    11 void read(T &x){
    12     char c;
    13     bool op = 0;
    14     while(c = getchar(), c < '0' || c > '9')
    15     if(c == '-') op = 1;
    16         x = c - '0';
    17     while(c = getchar(), c >= '0' && c <= '9')
    18         x = x * 10 + c - '0';
    19     if(op) x = -x;
    20 }
    21 template <class T>
    22 void write(T x){
    23     if(x < 0) putchar('-'), x = -x;
    24     if(x >= 10) write(x / 10);
    25     putchar('0' + x % 10);
    26 }
    27 const int N = 1000005;
    28 const double PI = acos(-1);
    29 typedef complex <double> cp;
    30 char sa[N], sb[N];
    31 int n = 1, lena, lenb, res[N];
    32 cp a[N], b[N], omg[N], inv[N];
    33 void init(){
    34     for(int i = 0; i < n; i++){
    35         omg[i] = cp(cos(2 * PI * i / n), sin(2 * PI * i / n));
    36         inv[i] = conj(omg[i]);
    37     }
    38 }
    39 void fft(cp *a, cp *omg){
    40     int lim = 0;
    41     while((1 << lim) < n) lim++;
    42     for(int i = 0; i < n; i++){
    43         int t = 0;
    44         for(int j = 0; j < lim; j++)
    45             if((i >> j) & 1) t |= (1 << (lim - j - 1));
    46         if(i < t) swap(a[i], a[t]); // i < t 的限制使得每对点只被交换一次(否则交换两次相当于没交换)
    47     }
    48     for(int l = 2; l <= n; l *= 2){
    49         int m = l / 2;
    50     for(cp *p = a; p != a + n; p += l)
    51         for(int i = 0; i < m; i++){
    52             cp t = omg[n / l * i] * p[i + m];
    53             p[i + m] = p[i] - t;
    54             p[i] += t;
    55         }
    56     }
    57 }
    58 int main(){
    59     scanf("%s%s", sa, sb);
    60     lena = strlen(sa), lenb = strlen(sb);
    61     while(n < lena + lenb) n *= 2;
    62     for(int i = 0; i < lena; i++)
    63         a[i].real(sa[lena - 1 - i] - '0');
    64     for(int i = 0; i < lenb; i++)
    65         b[i].real(sb[lenb - 1 - i] - '0');
    66     init();
    67     fft(a, omg);
    68     fft(b, omg);
    69     for(int i = 0; i < n; i++)
    70         a[i] *= b[i];
    71     fft(a, inv);
    72     for(int i = 0; i < n; i++){
    73         res[i] += floor(a[i].real() / n + 0.5);
    74         res[i + 1] += res[i] / 10;
    75         res[i] %= 10;
    76     }
    77     for(int i = res[lena + lenb - 1] ? lena + lenb - 1: lena + lenb - 2; i >= 0; i--)
    78         putchar('0' + res[i]);
    79     enter;
    80     return 0;
    81 }
    82 
    83 //可以预处理ωkn和ω−kn,分别存在omg和inv数组中。调用fft时,如果无需取倒数,则传入omg;如果需要取倒数,则传入inv。
    View Code
    ------------------------------------------------------------------------- 花有重开日,人无再少年
  • 相关阅读:
    (简单) POJ 3414 Pots,BFS+记录路径。
    (简单) POJ 3087 Shuffle'm Up,枚举。
    (简单) POJ 3126 Prime Path,BFS。
    (简单) POJ 1426 Find The Multiple,BFS+同余。
    (简单) POJ 3279 Fliptile,集合枚举。
    (简单) POJ 1278 Catch That Cow,回溯。
    (简单) POJ 2251 Dungeon Master,BFS。
    (简单) POJ 1321 棋盘问题,回溯。
    回溯---输出二叉树中所有从根到叶子的路径
    回溯---在矩阵中寻找字符串
  • 原文地址:https://www.cnblogs.com/lbz007oi/p/12288348.html
Copyright © 2011-2022 走看看