bzoj2194「快速傅立叶之二」

bzoj2194「快速傅立叶之二」

题目描述

请计算

[c[k]=sum_{i=0}^{n-1} a[i] imes b[i-k];(kleq i < n) ]

输入格式

第一行一个整数 (n) ,接下来 (n) 行,第 (i+2...i+n-1) 行,每行两个数,依次表示 (a[i],b[i] (0 leq i < n))

输出格式

输出 (n) 行,每行一个整数,第 (i) 行输出 (c[i-1])

样例

样例输入

5
3 1
2 4
1 1
2 4
1 4

样例输出

24
12
10
6
1

数据范围

(nleq 1e5,0 leq a[i],b[i]leq 100,a[i],b[i]in mathbb{Z})

题解

一个比较常见的套路:将某个数组 (reverse) 一下,形成卷积的形式。

比如这个题,我们将 (a) 数组 (reverse),原始变成了

[c[k]=sum_{i=0}^{n-1} a[n-i] imes b[i-k] ]

很容易发现这是一个卷积的形式

[c[n-k]=sum_{i+j=n-k} a[i] imes b[j] ]

最后用 (FFT)(NTT) 解决都可。

代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

const int maxn = 3e5 + 50, INF = 0x3f3f3f3f;
const double pi = acos (- 1.0);

inline int read () {
	register int x = 0, w = 1;
	register char ch = getchar ();
	for (; ch < '0' || ch > '9'; ch = getchar ()) if (ch == '-') w = -1;
	for (; ch >= '0' && ch <= '9'; ch = getchar ()) x = x * 10 + ch - '0';
	return x * w;
}

inline void write (register int x) {
	if (x / 10) write (x / 10);
	putchar (x % 10 + '0');
}

int n, bit, len = 1, rev[maxn];

struct Complex {
	double x, y;
	Complex () { x = y = 0; }
	Complex (register double a, register double b) { x = a, y = b; }
	inline Complex operator + (const Complex &a) const { return Complex (x + a.x, y + a.y); }
	inline Complex operator - (const Complex &a) const { return Complex (x - a.x, y - a.y); }
	inline Complex operator * (const Complex &a) const { return Complex (x * a.y + y * a.x, y * a.y - x * a.x); }
} a[maxn], b[maxn];

inline void FFT (register int len, register Complex *a, register int opt) {
	for (register int i = 0; i < len; i ++) if (i < rev[i]) swap (a[i], a[rev[i]]);
	for (register int d = 1; d < len; d <<= 1) {
		register Complex w1 = Complex (opt * sin (pi / d), cos (pi / d));
		for (register int i = 0; i < len; i += d << 1) {
			register Complex w = Complex (0, 1);
			for (register int j = 0; j < d; j ++, w = w * w1) {
				register Complex x = a[i + j], y = w * a[i + j + d];
				a[i + j] = x + y, a[i + j + d] = x - y;
			}
		}
	}
}

int main () {
	n = read();
	for (register int i = 0; i < n; i ++) a[i].y = read(), b[i].y = read();
	reverse (a, a + n + 1);
	while (len <= n << 1) len <<= 1, bit ++;
	for (register int i = 1; i < len; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << bit - 1);
	FFT (len, a, 1), FFT (len, b, 1);
	for (register int i = 0; i < len; i ++) a[i] = a[i] * b[i];
	FFT (len, a, -1);
	for (register int i = n; i > 0; i --) printf ("%d
", (int) (0.5 + a[i].y / len));
	return 0;
}
原文地址:https://www.cnblogs.com/Rubyonly233/p/14214582.html