A*B Problem 升级版 FFT

题目链接:https://www.luogu.org/problem/P1919

题目描述
给出两个n位10进制整数x和y,你需要计算 x ∗ y x*y xy
输入格式
第一行一个正整数n。 第二行描述一个位数为n的正整数x。 第三行描述一个位数为n的正整数y。
输出格式
输出一行,即x*y的结果。(注意判断前导0)

输入
1 3 4
输出
12
数据范围:
n<=60000

对于每一个nn位的十进制数,我们可以看做一个n-1n−1次多项式AA,满足
A ( x ) = a 0 + a 1 × 10 + a 2 × 1 0 2 ⋯ + a n − 1 × 1 0 n − 1 A(x) =a_0+a_1 \times 10+a_2\times10^2 \cdots +a_{n-1}\times10^{n-1} A(x)=a0+a1×10+a2×102+an1×10n1

那么对于两个大整数相乘,我们就可以卷起来
小细节:
·不要忘记进位
·不要忘了要保证数位上的单调性,因为我们普通的FFT卷积时,高次项一定由低次项得到,放在这里也一样,所以我们要倒序存储。

#include <stdio.h>
#include <math.h>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
const int mx = 4e6;
const double pi = acos(-1.0);

struct co {
    double x, y;
    co(){}
    co (double xx, double yy):x(xx),y(yy) {}
    co operator+(const co &a) const {
        return co(x+a.x, y+a.y);
    }
    co operator-(const co &a) const {
        return co(x-a.x, y-a.y);
    }
    co operator*(const co &a) const {
        return co(x*a.x-y*a.y, x*a.y+a.x*y);
    }
} a[mx], b[mx];
int r[mx];
void fft(co *a, int n, int type) {
    for (int i = 0; i < n; ++i) if (i < r[i]) swap(a[i], a[r[i]]);
    for (int i = 2; i <= n; i<<=1) {
        co wn(cos(2*pi/i), type*sin(2*pi/i));
        for (int j = 0; j < n; j += i) {
            co w(1, 0);
            int mit = i>>1;
            for (int z = 0; z < mit; ++z, w = w*wn) {
                co x = a[j+z], y = w*a[j+mit+z];
                a[j+z] = x+y;
                a[j+mit+z] = x-y;
            }
        }
    }
    return;
}
string s1, s2;
int main() {
    int n, mt = 1, I = 0;
    scanf("%d", &n);
    while (mt < 2*n) mt<<=1, I++;
    for (int i = 0; i < mt; ++i) r[i] = (r[i>>1]>>1)|(i&1)<<(I-1);
    cin >> s1 >> s2;
    reverse(s1.begin(), s1.end());
    reverse(s2.begin(), s2.end());
    for (int i = 0; i < n; ++i) a[i].x = s1[i]-'0', b[i].x = s2[i]-'0';
    fft(a, mt, 1);
    fft(b, mt, 1);
    for (int i = 0; i < mt; ++i) a[i] = a[i]*b[i];
    fft(a, mt, -1);
    s1 = "";
    memset(r, 0, sizeof(r));
    for (int i = 0; i < mt; ++i) {
        r[i] += a[i].x/mt+0.5;
        r[i+1] += r[i]/10;
        r[i] %= 10;
    }
    bool f = 0;
    for (int i = mt; i--;) {
        if (r[i]) f =true;
        if (f) printf("%d", r[i]);
    }
    puts("");
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值