【luogu P1919】【模板】A*B Problem升级版(FFT快速傅里叶)

【模板】A*B Problem升级版(FFT快速傅里叶)

题目链接:luogu P1919

题目大意

给你 a,b 两个数,要你求 a*b。
数很大。

思路

就是把每一位当做一项,然后做 FFT,然后不要忘记进位就可以了。
(记得倒叙储存)

代码

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

using namespace std;

struct complex {
	double x, y;
	complex (double X = 0, double Y = 0) {x = X; y = Y;}
}a[4000005], b[4000005];
char as[1000001], bs[1000001];
int an, bn, limit, ln, ann[4000001], ans[4000005];
double Pi = acos(-1.0);

complex operator +(complex x, complex y) {
	return complex(x.x + y.x, x.y + y.y);
}

complex operator -(complex x, complex y) {
	return complex(x.x - y.x, x.y - y.y);
}

complex operator *(complex x, complex y) {
	return complex(x.x * y.x - x.y * y.y, x.x * y.y + x.y * y.x);
}

void FFT(complex *now, int op) {
	for (int i = 0; i < limit; i++)
		if (i > ann[i]) swap(now[i], now[ann[i]]);
	
	for (int mid = 1; mid < limit; mid <<= 1) {
		complex Wn(cos(Pi / mid), op * sin(Pi / mid));
		for (int R = (mid << 1), j = 0; j < limit; j += R) {
			complex w(1, 0);
			for (int k = 0; k < mid; k++, w = w * Wn) {
				complex x = now[j + k], y = w * now[j + mid + k];
				now[j + k] = x + y; now[j + mid + k] = x - y;
			}
		}
	}
}

int main() {
	scanf("%s\n%s", &as, &bs);
	an = strlen(as) - 1; bn = strlen(bs) - 1;
	
	for (int i = 0; i <= an; i++)//倒叙储存
		a[an - i].x = as[i] - '0';
	for (int i = 0; i <= bn; i++)
		b[bn - i].x = bs[i] - '0';
	
	limit = 1;
	while (limit < an + bn) {
		limit <<= 1;
		ln++;
	}
	
	for (int i = 0; i < limit; i++)
		ann[i] = (ann[i >> 1] >> 1) | ((i & 1) << (ln - 1));
	
	FFT(a, 1); FFT(b, 1);
	for (int i = 0; i <= limit; i++)
		a[i] = a[i] * b[i];
	FFT(a, -1);
	
	for (int i = 0; i <= limit; i++) {
		ans[i] += (int)(a[i].x / limit + 0.5);
		if (ans[i] >= 10) {//进位
			ans[i + 1] += ans[i] / 10;
			ans[i] %= 10;
			if (i == limit) limit++;
		}
	}
	
	while (limit && !ans[limit]) limit--;
	for (int i = 0; i <= limit; i++)
		printf("%d", ans[limit - i]);
	
	return 0;
}
posted @ 2021-08-24 09:28  あおいSakura  阅读(38)  评论(0编辑  收藏  举报