题目链接:https://www.luogu.org/problem/P1919
题目描述
给出两个n位10进制整数x和y,你需要计算
x
∗
y
x*y
x∗y。
输入格式
第一行一个正整数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⋯+an−1×10n−1
那么对于两个大整数相乘,我们就可以卷起来
小细节:
·不要忘记进位
·不要忘了要保证数位上的单调性,因为我们普通的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("");
}