bzoj4827 Hnoi2017 礼物

题目链接

solution

将式子展开

\[\sum\limits_{i=1}^n(x_i - y_i + c)^2 \]

\[=\sum\limits_{i=1}^nx_i^2+y_i^2-2x_iy_i+2c(x_i-y_i)+c^2 \]

\[=\sum\limits_{i=1}^nx_i^2+\sum\limits_{i=1}^ny_i^2-2\sum\limits_{i=1}^nx_iy_i+2c(\sum\limits_{i=1}^nx_i-\sum\limits_{i=1}^ny_i)+nc^2 \]

前面\(\sum\limits_{i=1}^nx_i^2+\sum\limits_{i=1}^ny_i^2\)是定值。
后面\(2c(\sum\limits_{i=1}^nx_i-\sum\limits_{i=1}^ny_i)+nc^2\)是个二次函数。最值很好求。
所以问题就是要最大化\(\sum\limits_{i=1}^nx_iy_i\),

我们设将\(y\)这个手环左移了\(k\)下。那么答案就变为\(\sum\limits_{i=1}^nx_iy_{i+k}\)

将x序列倒过来就变成了卷积的形式\(\sum\limits_{i=1}^nx_{n-i}y_{i+k}\)

code

/*
* @Author: wxyww
* @Date:   2019-07-21 20:49:19
* @Last Modified time: 2019-07-21 21:33:06
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
#include<cmath>
using namespace std;
typedef long long ll;
const int N = 1000000 + 100;
ll read() {
	ll x=0,f=1;char c=getchar();
	while(c<'0'||c>'9') {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9') {
		x=x*10+c-'0';
		c=getchar();
	}
	return x*f;
}
int Re[N],n,m,limit = 1;
struct complex {
	double x,y;
	complex(double xx = 0,double yy = 0) {x = xx;y = yy;}
}a[N],b[N];
complex operator + (const complex &A,const complex &B) {
	return complex(A.x + B.x,A.y + B.y);
}
complex operator - (const complex &A,const complex &B) {
	return complex(A.x - B.x,A.y - B.y);
}
complex operator * (const complex &A,const complex &B) {
	return complex(A.x * B.x - A.y * B.y,A.x * B.y + A.y * B.x);
}
double ans;
double T;
const double pi = acos(-1.0);
void FFT(complex *A,int type) {
	for(int i = 0;i < limit;++i) if(i < Re[i]) swap(A[i],A[Re[i]]);
	for(int mid = 1;mid < limit;mid <<= 1) {
		complex Wn(cos(pi / mid),type * sin(pi / mid));
		for(int R = mid << 1,j = 0;j < limit;j += R) {
			complex w(1.0,0);
			for(int k = 0;k < mid;++k,w = w * Wn) {
				complex x = A[j + k],y = w * A[j + mid + k];
				A[j + mid + k] = x - y;
				A[j + k] = x + y;
			}
		}
	}
}
ll calc(ll x) {
	return n * x * x + 2 * T * x;
}
int main() {
	n = read(),m = read();
	for(int i = 0;i < n;++i) {
		int x = read();
		a[n - i].x = x;
		ans += x * x;
		T += x;
	}

	for(int i = 0;i < n;++i) {
		int y = read();
		b[i].x = b[i + n].x = y;
		ans += y * y;
		T -= y;
	}

	int num = 0;
	while(limit <= n * 3) limit <<= 1,num++;
	for(int i = 0;i <= limit;++i) Re[i] = Re[i >> 1] >> 1 | ((i & 1) << (num - 1));

	FFT(a,1);
	FFT(b,1);
	for(int i = 0;i <= limit;++i) a[i] = a[i] * b[i];
	FFT(a,-1);

	double ret = 0;
	for(int i = 0;i <= limit;++i) ret = max(ret,round(a[i].x / limit));

	ans -= 2 * ret;
	
	ans += calc(round(-T / n));

	printf("%.0lf",ans);

	return 0;
}
posted @ 2019-07-21 21:56  wxyww  阅读(...)  评论(...编辑  收藏