P3723 [AH2017/HNOI2017]礼物

(color{#0066ff}{ 题目描述 })

我的室友最近喜欢上了一个可爱的小女生。马上就要到她的生日了,他决定买一对情侣手环,一个留给自己,一个送给她。每个手环上各有 n 个装饰物,并且每个装饰物都有一定的亮度。

但是在她生日的前一天,我的室友突然发现他好像拿错了一个手环,而且已经没时间去更换它了!他只能使用一种特殊的方法,将其中一个手环中所有装饰物的亮度增加一个相同的自然数 c(即非负整数)。并且由于这个手环是一个圆,可以以任意的角度旋转它,但是由于上面装饰物的方向是固定的,所以手环不能翻转。需要在经过亮度改造和旋转之后,使得两个手环的差异值最小。

在将两个手环旋转且装饰物对齐了之后,从对齐的某个位置开始逆时针方向对装饰物编号1,2,…,n,其中 n 为每个手环的装饰物个数, 第 1 个手环的 i 号位置装饰物亮度为 xi,第 2 个手环的 i 号位置装饰物亮度为 yi,两个手环之间的差异值为(参见输入输出样例和样例解释):

(sum_{i=1}^{n} (x_i-y_i)^2)

麻烦你帮他计算一下,进行调整(亮度改造和旋转),使得两个手环之间的差异值最小,这个最小值是多少呢?

(color{#0066ff}{输入格式})

输入数据的第一行有两个数n, m,代表每条手环的装饰物的数量为n,每个装饰物的初始亮度小于等于m。

接下来两行,每行各有n个数,分别代表第一条手环和第二条手环上从某个位置开始逆时针方向上各装饰物的亮度。

(color{#0066ff}{输出格式})

输出一个数,表示两个手环能产生的最小差异值。注意在将手环改造之后,装饰物的亮度

可以大于 m。

(color{#0066ff}{输入样例})

5 6
1 2 3 4 5
6 3 3 4 5

(color{#0066ff}{输出样例})

1

(color{#0066ff}{数据范围与提示})

需要将第一个手环的亮度增加1,第一个手环的亮度变为: 2 3 4 5 6

旋转一下第二个手环。对于该样例,是将第二个手环的亮度6 3 3 4 5向左循环移动一个位置,使得第二手环的最终的亮度为: 3 3 4 5 6。

此时两个手环的亮度差异值为1

30%的数据满足n≤500, m≤10;

70%的数据满足n≤5000;

100%的数据满足1≤n≤50000, 1≤m≤100, 1≤ai≤m。

(color{#0066ff}{ 题解 })

设我们对某一手环+c(如果最后c是负的就是对另一个加,正负不影响)

则差异值为(sum(x_i-y_i+c))

展开

(sum x_i^2 + sum y_i^2 -2sum x_i y_i+ n*c^2+2*(sum x_i-y_i)*c)

卧槽,除了(-2sum x_i y_i)之外都是定值

老规矩,把其中一个翻转一下(为了匹配,延长一倍)

FFT一下,然后get这个的最小值

之后枚举c更新ans就行了(二次函数qwq)

#include<bits/stdc++.h>
#define LL long long
LL in() {
	char ch; LL x = 0, f = 1;
	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
	return x * f;
}
using std::vector;
const int mod = 998244353;
const int maxn = 2e5 + 100;
int len, r[maxn];
LL ksm(LL x, LL y) {
	LL re = 1LL;
	while(y) {
		if(y & 1) re = re * x % mod;
		x = x * x % mod;
		y >>= 1;
	}
	return re;
}
void FNTT(vector<int> &A, int flag) {
	A.resize(len);
	for(int i = 0; i < len; i++) if(i < r[i]) std::swap(A[i], A[r[i]]);
	for(int l = 1; l < len; l <<= 1) {
		int w0 = ksm(3, (mod - 1) / (l << 1));
		for(int i = 0; i < len; i += (l << 1)) {
			int w = 1, a0 = i, a1 = i + l;
			for(int k = 0; k < l; k++, a0++, a1++, w = 1LL * w * w0 % mod) {
				int tmp = 1LL * A[a1] * w % mod;
				A[a1] = ((A[a0] - tmp) % mod + mod) % mod;
				A[a0] = (A[a0] + tmp) % mod;
			}
		}
	}
	if(flag == -1) {
		std::reverse(A.begin() + 1, A.end());
		int inv = ksm(len, mod - 2);
		for(int i = 0; i < len; i++) A[i] = 1LL * inv * A[i] % mod;
	}
}
vector<int> operator * (vector<int> A, vector<int> B) {
	int tot = A.size() + B.size() - 1;
	for(len = 1; len <= tot; len <<= 1);
	for(int i = 0; i < len; i++) r[i] = (r[i >> 1] >> 1) | ((i & 1) * (len >> 1));
	FNTT(A, 1), FNTT(B, 1);
	vector<int> ans;
	ans.resize(len);
	for(int i = 0; i < len; i++) ans[i] = 1LL * A[i] * B[i] % mod;
	FNTT(ans, -1);
	ans.resize(tot);
	return ans;
}
const LL inf = 999999999999999LL;
int main() {
	static int A[maxn], B[maxn];
	int n = in(), m = in();
	vector<int> a, b, c, d;
	LL aa = 0, bb = 0, sa = 0, sb = 0;;
	for(int i = 0; i < n; i++) a.push_back(A[i] = in()), aa += A[i] * A[i], sa += A[i];
	for(int i = 0; i < n; i++) b.push_back(B[i] = in()), bb += B[i] * B[i], sb += B[i];
	c = a, d = b;
	std::reverse(c.begin(), c.end());
	for(int i = 0; i < n; i++) d.push_back(b[i]);
	vector<int> ans = c * d;
	LL tot = inf, old = inf;
	for(int i = n; i < n + n; i++) old = std::min(old, -2LL * ans[i]);
	LL cc = (sb - sa) / n;
		for(LL i = cc - 10; i <= cc + 10; i++) tot = std::min(tot, aa + bb + old + i * i * n + 2LL * (sa - sb) * i);
	printf("%lld
", tot);
	return 0;	
}
原文地址:https://www.cnblogs.com/olinr/p/10276717.html