[HDU1402]A * B Problem Plus

这篇博客讨论了如何解决A * B的问题,其中A和B的位数不超过50000。提出了两种解决方案,一是传统的高精度乘法,其时间复杂度为O(n^2),二是利用快速傅里叶变换(FFT)的方法,时间复杂度降低到O(nlogn)。通过将数的每一位转换为多项式系数,然后计算乘积,最后处理进位,实现高效计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem description

Link
计算A*B,其中A,B的位数不超过50000

Possible Solution

高精乘:时间复杂度O(n^2)

FFT :时间复杂度O(nlogn)

将A,B两数的每个位当做多项式A(X),B(X)的系数,计算出A(X)*B(X)的系数,在进行进位。记得到C

附代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define Maxlen 50005
const double PI = acos(-1.0);
struct complex{
    double r,i;
    complex(double _r = 0.0, double _i = 0.0): r(_r),i(_i) {}
};
complex operator * (complex &a, complex &b) {
    return complex(a.r * b.r - a.i * b.i, a.r * b.i + a.i * b.r);
}
complex operator + (complex &a, complex &b) {
    return complex(a.r + b.r , a.i + b.i);
}
complex operator - (complex &a, complex &b) {
    return complex(a.r - b.r , a.i - b.i);
}

class Solution{
private:
    complex a[Maxlen], b[Maxlen];
    int n;
    int c[Maxlen*2];
public:
    Solution(char *s1, char *s2) {
        int len1 = strlen(s1);
        for (int i = 0; i < len1; ++i)
            a[i] = complex(s1[len1 - 1 - i] - '0', 0);
        int len2 = strlen(s2);
        for (int i = 0; i < len2; ++i)
            b[i] = complex(s2[len2 - 1 - i] - '0', 0);
        n = std::max(len1, len2)*2;
        int x = 0;
        while ((1<<x) < n) x++;
        n = 1 << x;
        for (;len1 < n; ++len1) a[len1] = complex(0,0);
        for (;len2 < n; ++len2) b[len2] = complex(0,0);
    }
    void reverse(complex *a) {
        for(int i = 1, j = n/2; i < n-1; i++) {
            if(i < j) std::swap(a[i],a[j]);
            int k = n/2;
            for (;j >= k; j -= k,k /= 2);
            if(j < k) j += k;
        }
    }
    void fft(complex *a, int f) {
        reverse(a);
        for(int i = 2; i <= n; i <<= 1) {
            complex wn(cos(-f*2*PI/i),sin(-f*2*PI/i));
            for(int j = 0; j < n; j += i) {
                complex w(1,0);
                for(int k = j;k < j+i/2; k++) {
                    complex x = a[k];
                    complex y = w * a[k+i/2];
                    a[k] = x + y;
                    a[k+i/2] = x - y;
                    w = w * wn;
                }
            }
        }
        if(f == -1)
            for(int i = 0; i < n; i++)
                a[i].r /= n;
    }
    void solve() {
        fft(a, 1);
        fft(b, 1);
        for (int i = 0; i < n; ++i)
            a[i] = a[i] * b[i];
        fft(a,-1);
        int x = 0;
        memset(c, 0, sizeof(c));
        for (int i = 0; i < n; ++i) {
            c[i] = (int)(a[i].r + 0.5) + x;
            x = c[i] / 10;
            c[i] = c[i] % 10;
        }
        n = 2*n;
        while (c[n-1] <= 0 && n-1 > 0) --n;
        while (n-1 >= 0) printf("%d", c[--n]);
        printf("\n");
    }
};
char s1[Maxlen], s2[Maxlen];
int main(){
    while (scanf("%s", s1) != EOF){
        scanf("%s", s2);
        Solution solution(s1,s2);
        solution.solve();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值