「HDU 1402」A * B Problem Plus

这个标题是唬人玩儿的,虽然这题。。。名副其实

题意

这道题题意是大整数乘法。多组输入,每次输入两个数,一直处理到EOF为止。每组输入的数字的长度不超过50000。

思路

开头就已经写清楚了,这是个快速傅立叶变换的板题。当然,不知道压个八九位用long long能不能暴力过QwQ

FFT本来就是处理多项式乘法的系数的,多项式乘法的系数运算恰好和整数乘法一致,所以就分别把两个数反转,然后用FFT求出它们相乘以后的值,然后再反转回来。

不要忘记它们做完乘法后可能会出现进位,所以记得处理进位(我的第一次WA)

然后别忘了初始化(第二次WA)

另外就是HDU的cmath库里没有M_PI(这得多老了),所以自定义一下PI(下面这个值是我直接把M_PI给复制过来了)。

FFT的板子是从OI-Wiki抄的,复数是我自己写的。

代码

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>

const double PI = 3.14159265358979323846264338327950288;
using namespace std;

const int maxn = 4e5 + 5;
int rev[maxn];

struct Complex {
    double x, y;
    Complex(double x = 0.0, double y = 0.0): x(x), y(y) {}

    Complex operator + (const Complex &rhs) {
        return Complex(this->x + rhs.x, this->y + rhs.y);
    }
    Complex operator - (const Complex &rhs) {
        return Complex(this->x - rhs.x, this->y - rhs.y);
    }
    Complex operator * (const Complex &rhs) {
        return Complex(this->x * rhs.x - this->y * rhs.y, this->x * rhs.y + this->y * rhs.x);
    }
    Complex operator / (const double rhs) {
        return Complex(this->x / rhs, this->y / rhs);
    }
};

void change(Complex y[], int len) {
    for (int i = 0; i < len; i++) {
        rev[i] = rev[i >> 1] >> 1;
        if (i & 1)
            rev[i] |= len >> 1;
    }
    for (int i = 0; i < len; i++) {
        if (i < rev[i])
            swap(y[i], y[rev[i]]);
    }
}

void FFT(Complex y[], int len, int on) {
    change(y, len);
    for (int h = 2; h <= len; h <<= 1) {
        Complex wn(cos(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;
        }
    }
}

char str1[maxn], str2[maxn];
Complex a[maxn], b[maxn];
int n, m, limit;
int ans[maxn];

void Assign(char *str, Complex x[], int len) {
    for (int i = 0; i < len; i++) {
        x[i].x = (double)(str[len - i - 1] - '0');
        x[i].y = 0.0;
    }
}

inline void init() {
    for (int i = n; i <= limit; i++) a[i].x = a[i].y = 0.0;
    for (int i = m; i <= limit; i++) b[i].x = b[i].y = 0.0;
    memset(ans, 0, (limit << 2));
}

int main() {
    while (scanf("%s%s", str1, str2) == 2) {
        n = strlen(str1);
        m = strlen(str2);
        limit = 1;
        while (limit <= n + m) limit <<= 1;
        init();
        Assign(str1, a, n);
        Assign(str2, b, m);

        FFT(a, limit, 1);
        FFT(b, limit, 1);
        for (int i = 0; i < limit; i++)
            a[i] = a[i] * b[i];
        FFT(a, limit, -1);
        for (int i = 0; i < limit; i++)
            ans[i] = int(a[i].x + 0.5);
        
        for (int i = 0; i < limit; i++) {
            ans[i + 1] += ans[i] / 10;
            ans[i] %= 10;
        }

        // 这里len必须初始化为n + m - 1,因为上一次n + m的值可能不为0,而且init的时候没有处理n + m - 1后面的数据
        // 就这一个破地方我调试了半个小时
        // 说到底还是太菜QAQ
        int len = n + m - 1;
        while (!ans[len] && len > 0) len--;

        for (int i = len; i >= 0; i--)
            putchar(ans[i] + '0');
        putchar('
');
    }
    return 0;
}
原文地址:https://www.cnblogs.com/icysky/p/14018045.html