bzoj2194「快速傅立叶之二」

题目描述

请计算

\[c[k]=\sum_{i=0}^{n-1} a[i]\times b[i-k]\;(k\leq 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

数据范围

\(n\leq 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]\times b[i-k] \]

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

\[c[n-k]=\sum_{i+j=n-k} a[i]\times 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\n", (int) (0.5 + a[i].y / len));
	return 0;
}
posted @ 2020-12-31 09:10  Rubyonlу  阅读(76)  评论(0编辑  收藏  举报