【CodeVS 3123】高精度练习之超大整数乘法 &【BZOJ 2197】FFT快速傅立叶

第一次写法法塔,,,感到威力无穷啊

看了一上午算导就当我看懂了?PS:要是机房里能有个清净的看书环境就好了

FFT主要是用了巧妙的复数单位根,复数单位根在复平面上的对称性使得快速傅立叶变换的时间复杂度空降为O(nlogn)←个人的愚蠢理解请随意吐槽

具体的我就不说了,算导上都说得很清楚,说得好像有人会听我说什么似的

模板在这里↓

CodeVS 3123:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1E6 + 3;
const double Pi = acos(- 1.0);
struct cp {
	double r, i;
	cp(double _r = 0.0, double _i = 0.0) : r(_r), i(_i) {}
	cp operator + (const cp &x) const {return cp(r + x.r, i + x.i);}
	cp operator - (const cp &x) const {return cp(r - x.r, i - x.i);}
	cp operator * (const cp &x) const {return cp(r * x.r - i * x.i, r * x.i + i * x.r);}
};
char s[N];
int rev[N];
cp A[N];
void DFT(cp *a, int n, int flag) {
	for(int i = 0; i < n; ++i) A[rev[i]] = a[i];
	for(int i = 0; i < n; ++i) a[i] = A[i];
	for(int m = 2, mid; m <= n; m <<= 1) {
		cp wn(cos(2.0 * Pi / m * flag), sin(2.0 * Pi / m * flag));
		mid = m >> 1;
		for(int i = 0; i < n; i += m) {
			cp w(1.0);
			for(int j = 0; j < mid; ++j) {
				cp u = a[i + j + mid] * w, t = a[i + j];
				a[i + j] = t + u;
				a[i + j + mid] = t - u;
				w = w * wn;
			}
		}
	}
	if (flag == -1)
		for(int i = 0; i < n; ++i)
			a[i].r /= n;
}

void in(cp *a, int &n) {
	scanf("%s", s);
	n = strlen(s);
	for(int i = 0; i < n; ++i)
		a[i].r = s[n - i - 1] - '0';
}
void init(int &n) {
	int k = 1, L = 0;
	for(; k < n; k <<= 1, ++L);
	n = k;
	for(int i = 0; i < n; ++i) {
		int t = i, ret = 0;
		for(int j = 0; j < L; ++j)
			ret <<= 1, ret |= (t & 1), t >>= 1;
		rev[i] = ret;
	}
}
cp a[N], b[N];
int len = -1, n, ans[N];
void FFT() {
	DFT(a, len, 1); DFT(b, len, 1);
	for(int i = 0; i < len; ++i)
		a[i] = a[i] * b[i];
	DFT(a, len, -1);
}
int main() {
	in(a, n); len += n;
	in(b, n); len += n;
	init(len);
	FFT();
	for(int i = 0; i < len; ++i)
		ans[i] = (int) (a[i].r + 0.5);
	for(int i = 0; i < len; ++i)
		ans[i + 1] += ans[i] / 10, ans[i] %= 10;
	for(++len; ans[len] == 0 && len > 0; --len);
	for(int i = len; i >= 0; --i)
		printf("%d", ans[i]);
	puts("");
	return 0;
}

BZOJ 2197顺便水一水~:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1E6 + 3;
const double Pi = acos(- 1.0);
struct cp {
	double r, i;
	cp(double _r = 0.0, double _i = 0.0) : r(_r), i(_i) {}
	cp operator + (const cp &x) const {return cp(r + x.r, i + x.i);}
	cp operator - (const cp &x) const {return cp(r - x.r, i - x.i);}
	cp operator * (const cp &x) const {return cp(r * x.r - i * x.i, r * x.i + i * x.r);}
};
char s[N];
int rev[N];
cp A[N];
void DFT(cp *a, int n, int flag) {
	for(int i = 0; i < n; ++i) A[rev[i]] = a[i];
	for(int i = 0; i < n; ++i) a[i] = A[i];
	for(int m = 2, mid; m <= n; m <<= 1) {
		cp wn(cos(2.0 * Pi / m * flag), sin(2.0 * Pi / m * flag));
		mid = m >> 1;
		for(int i = 0; i < n; i += m) {
			cp w(1.0);
			for(int j = 0; j < mid; ++j) {
				cp u = a[i + j + mid] * w, t = a[i + j];
				a[i + j] = t + u;
				a[i + j + mid] = t - u;
				w = w * wn;
			}
		}
	}
	if (flag == -1)
		for(int i = 0; i < n; ++i)
			a[i].r /= n;
}

void in(cp *a, int &n) {
	scanf("%s", s);
	n = strlen(s);
	for(int i = 0; i < n; ++i)
		a[i].r = s[n - i - 1] - '0';
}
void init(int &n) {
	int k = 1, L = 0;
	for(; k < n; k <<= 1, ++L);
	n = k;
	for(int i = 0; i < n; ++i) {
		int t = i, ret = 0;
		for(int j = 0; j < L; ++j)
			ret <<= 1, ret |= (t & 1), t >>= 1;
		rev[i] = ret;
	}
}
cp a[N], b[N];
int len = -1, n, ans[N];
void FFT() {
	DFT(a, len, 1); DFT(b, len, 1);
	for(int i = 0; i < len; ++i)
		a[i] = a[i] * b[i];
	DFT(a, len, -1);
}
int main() {
	scanf("%d\n", &len); len = (len << 1) - 1;
	in(a, n);
	in(b, n);
	init(len);
	FFT();
	for(int i = 0; i < len; ++i)
		ans[i] = (int) (a[i].r + 0.5);
	for(int i = 0; i < len; ++i)
		ans[i + 1] += ans[i] / 10, ans[i] %= 10;
	for(++len; ans[len] == 0 && len > 0; --len);
	for(int i = len; i >= 0; --i)
		printf("%d", ans[i]);
	puts("");
	return 0;
}

高一下半学期开学前的晚上就在看这个东西,拖到现在才理解,累啊~

posted @ 2016-04-25 17:35  abclzr  阅读(409)  评论(0编辑  收藏  举报