【LG3723】[AHOI2017/HNOI2017]礼物

【LG3723】[AHOI2017/HNOI2017]礼物

题面

洛谷

题解

首先我们将\(c\)看作一个可以为负的整数,那么我们就可以省去讨论在哪个手环加\(c\)的繁琐步骤了

设我们当前已经选好了手环的顺序

\[Ans=\sum_{i=1}^n(x_i-y_i+c)^2\\ =\sum_{i=1}^nx_i^2+\sum_{i=1}^ny_i^2+n*c^2+2c\sum_{i=1}^n(x_i-y_i)-2\sum_{i=1}^nx_i*y_i \]

实际上,因为前面都是定值(\(C\)的取值可以枚举),所以要求

\[\sum_{i=1}^nx_i*y_i \]

最大就行了。

我们将\(y_i\)反向,那么原式就是一个卷积。

这里有个很巧妙的\(trick\):将\(y\)再倍长一下,取\(x*y\)中第\(n+1\)\(2n\)项的最小值即可,这样

就很巧妙地模拟了翻转的过程

代码

#include <iostream> 
#include <cstdio> 
#include <cstdlib> 
#include <cstring> 
#include <cmath> 
#include <algorithm> 
using namespace std; 
inline int gi() {
	register int data = 0, w = 1;
	register char ch = 0;
	while (!isdigit(ch) && ch != '-') ch = getchar(); 
	if (ch == '-') w = -1, ch = getchar();
	while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
	return w * data; 
}
const double PI = acos(-1.0);
const int MAX_N = 2000005; 
struct Complex { double x, y; } a[MAX_N], b[MAX_N]; 
inline Complex operator + (const Complex &l, const Complex &r) { return (Complex){l.x + r.x, l.y + r.y}; }
inline Complex operator - (const Complex &l, const Complex &r) { return (Complex){l.x - r.x, l.y - r.y}; }
inline Complex operator * (const Complex &l, const Complex &r) { return (Complex){l.x * r.x - l.y * r.y, l.y * r.x + l.x * r.y}; } 
int n, m, N, M, s1[MAX_N], s2[MAX_N], r[MAX_N], res[MAX_N]; 
void FFT(Complex *p, int op) { 
	for (int i = 0; i < N; i++) if (i < r[i]) swap(p[i], p[r[i]]); 
	for (int i = 1; i < N; i <<= 1) {
		Complex rot = (Complex){cos(PI / i), op * sin(PI / i)};
		for (int tmp = i << 1, j = 0; j < N; j += tmp) { 
			Complex w = (Complex){1, 0}; 
			for (int k = 0; k < i; k++, w = w * rot) { 
				Complex x = p[j + k], y = w * p[i + j + k]; 
				p[j + k] = x + y, p[i + j + k] = x - y; 
			} 
		} 
	} 
} 
void Prepare () { 
	N = n - 1, M = n + n - 1; 
	for (int i = 0; i <= N; i++) a[i].x = s1[i + 1]; 
	for (int i = 0; i < n; i++) b[i].x = s2[n - i]; 
	for (int i = 0; i < n; i++) b[i + n] = b[i];
	int P = 0; 
	for (M += N, N = 1; N <= M; N <<= 1, ++P) ; 
	for (int i = 0; i < N; i++) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (P - 1)); 
	FFT(a, 1), FFT(b, 1); 
	for (int i = 0; i < N; i++) a[i] = a[i] * b[i]; 
	FFT(a, -1); 
	for (int i = 0; i <= M; i++) res[i] = (int)(a[i].x / N + 0.5); 
} 
int main () {
	n = gi(), m = gi(); 
	for (int i = 1; i <= n; i++) s1[i] = gi(); 
	for (int i = 1; i <= n; i++) s2[i] = gi(); 
	Prepare(); 
	int p1 = 0, p2 = 0, ans = 1e9, tmp1 = 0, tmp2 = 0, tt = -1e9;
	for (int i = 1; i <= n; i++) p1 += s1[i] * s1[i], p2 += s2[i] * s2[i], tmp1 += s1[i], tmp2 += s2[i]; 
	for (int i = n - 1; i < n + n; i++) tt = max(tt, res[i]); 
	for (int C = -m; C <= m; C++) {
		int tot = p1 + p2 + n * C * C + 2 * C * (tmp1 - tmp2) - 2 * tt; 
		ans = min(tot, ans); 
	} 
	printf("%d\n", ans); 
	return 0; 
} 
posted @ 2019-01-29 16:39  heyujun  阅读(137)  评论(0编辑  收藏  举报