• FFT实现高精度乘法


    你应该知道$FFT$是用来处理多项式乘法的吧。

    那么高精度乘法和多项式乘法有什么关系呢?

    观察这样一个$20$位高精度整数$11111111111111111111$

    我们可以把它处理成这样的形式:$sum_{i=0}^{19}1 imes10^i$

    这样就变成了一个多项式了!

    直接上代码吧(以$Luogu P1919$为例):

    #include <cmath>
    #include <cstdio>
    #include <algorithm>
    using std::swap;
    
    const int N = 1.4e5 + 10;
    const double Pi = acos(-1);
    int n, m, r[N], P, ans[N];
    char s[N];
    struct C { double x, y; } a[N], b[N];
    C operator + (C a, C b) { return (C){ a.x + b.x, a.y + b.y }; }
    C operator - (C a, C b) { return (C){ a.x - b.x, a.y - b.y }; }
    C operator * (C a, C b) { return (C){ a.x * b.x - a.y * b.y, a.x * b.y + b.x * a.y }; }
    
    void FFT(C f[], int opt) {
        for(int i = 0; i < n; ++i) if(i < r[i]) swap(f[i], f[r[i]]);
        for(int len = 1, nl = 2; len < n; len = nl, nl <<= 1) {
            C rot = (C){cos(Pi / len), opt * sin(Pi / len)};
            for(int l = 0; l < n; l += nl) {
                C w = (C){1, 0}; int r = l + len;
                for(int k = l; k < r; ++k, w = w * rot) {
                    C x = f[k], y = w * f[k + len];
                    f[k] = x + y, f[k + len] = x - y;
                }
            }
        }
    } 
    
    int main() {
        scanf("%d%s", &n, s + 1);
        for(int i = 1; i <= n; ++i) a[i - 1].x = s[n - i + 1] - '0';
        scanf("%s", s + 1);
        for(int i = 1; i <= n; ++i) b[i - 1].x = s[n - i + 1] - '0';
        //将字符串转化为多项式的系数
        --n;
        for(m = n + n, n = 1; n <= m; n <<= 1, ++P);
        for(int i = 0; i < n; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (P - 1));
        //蝴蝶变换FFT
        FFT(a, 1), FFT(b, 1);
        for(int i = 0; i < n; ++i) a[i] = a[i] * b[i];
        FFT(a, -1);
        for(int i = 0; i <= m; ++i) ans[i] = (int)(a[i].x / n + .5);
        for(int i = 0, tmp1, tmp2; i < m; ++i)
            ans[i + 1] += (ans[i] / 10), ans[i] %= 10;
        //处理进位(每个系数最多为两位数)
        for(int i = m, flag = 0; i >= 0; --i) {
            if(ans[i] != 0) flag = 1;
            else if(!flag) continue;
            printf("%d", ans[i]); 
        }//flag为前导零标记
        return puts("") & 0;
    }
    

    $PS:$代码中没有处理$0 imes0$的情况,请读者自行处理。

  • 相关阅读:
    SegmentFault 巨献 1024 程序猿游戏「红岸的呼唤」第二天任务攻略
    POJ 2263 Heavy Cargo(ZOJ 1952)
    EEPlat 主子表和对象引用配置实例
    tornado websocket
    android android:duplicateParentState=&quot;true&quot; &quot;false&quot;
    掌握4个有效的数据分析要点,切实解决用户痛点
    掌握4个有效的数据分析要点,切实解决用户痛点
    没有基础,如何成为数据分析师?
    没有基础,如何成为数据分析师?
    数据的无量纲化处理和标准化处理的区别是什么
  • 原文地址:https://www.cnblogs.com/water-mi/p/10198586.html
Copyright © 2020-2023  润新知