[HNOI2017]礼物

Description

我的室友最近喜欢上了一个可爱的小女生。马上就要到她的生日了,他决定买一对情侣手环,一个留给自己,一个送给她。每个手环上各有 n 个装饰物,并且每个装饰物都有一定的亮度。
但是在她生日的前一天,我的室友突然发现他好像拿错了一个手环,而且已经没时间去更换它了!他只能使用一种特殊的方法,将其中一个手环中所有装饰物的亮度增加一个相同的自然数 c(即非负整数)。并且由于这个手环是一个圆,可以以任意的角度旋转它,但是由于上面装饰物的方向是固定的,所以手环不能翻转。需要在经过亮度改造和旋转之后,使得两个手环的差异值最小。
在将两个手环旋转且装饰物对齐了之后,从对齐的某个位置开始逆时针方向对装饰物编号1,2,…,n,其中 n 为每个手环的装饰物个数, 第 1 个手环的 i 号位置装饰物亮度为 \(x_i\),第 2 个手环的 i 号位置装饰物亮度为 \(y_i\),两个手环之间的差异值为\(\sum_{i=1}^{n}(x_i-y_i)^2\)

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

HINT

\(1\leq n\leq50000, 1\leq m\leq100, 1\leq a_i\leq m\).

Solution

\(\begin{split}&\sum(x_i+c-y_i)^2\\=&\sum(x_i^2+y_i^2)+[nc^2+2c\sum(x_i-y_i)]-2\sum x_iy_i\end{split}\)

关于c的二次函数可以直接枚举求最值.

再求个循环卷积就解决了.

#define N 50005
#define K 131073
typedef long double ld;
const ld pi=acos(-1.0);
struct cp{
	ld x,y;
	cp() {}
	cp(ld x,ld y):x(x),y(y) {}
	friend cp operator + (cp a,cp b){
		return cp(a.x+b.x,a.y+b.y);
	}
	friend cp operator - (cp a,cp b){
		return cp(a.x-b.x,a.y-b.y);
	}
	friend cp operator * (cp a,cp b){
		return cp(a.x*b.x-a.y*b.y,a.y*b.x+a.x*b.y);
	}
}a1[K],b1[K],a2[K],b2[K];
namespace FFT{
	int re[K],n;cp w[2][K];
	inline void init(int k){
		k<<=1;n=1;while(n<k) n<<=1;
		for(int i=0;i<n;++i){
			w[0][i]=cp(cos(pi*2/n*i),sin(pi*2/n*i));
			w[1][i]=cp(w[0][i].x,-w[0][i].y);
		}
		k=0;while((1<<k)<n) ++k;
		for(int i=0,t;i<n;++i){
			t=0;
			for(int j=0;j<k;++j)
				if(i&(1<<j)) t|=(1<<k-j-1);
			re[i]=t;
		}
	}
	inline void DFT(cp *a,int ty){
		cp *o=w[ty];
		for(int i=0;i<n;++i)
			if(i<re[i]) swap(a[i],a[re[i]]);
		cp tmp;
		for(int l=2,m;l<=n;l<<=1){
			m=l>>1;
			for(cp *p=a;p!=a+n;p+=l)
				for(int i=0;i<m;++i){
					tmp=o[n/l*i]*p[i+m];
					p[i+m]=p[i]-tmp;p[i]=p[i]+tmp;
				}
		}
		if(ty) for(int i=0;i<n;++i)
			a[i].x/=(ld)(n),a[i].y/=(ld)(n);
	}
}
int x[N],y[N],n,m,ans,tot;
inline int read(){
	int ret=0;char c=getchar();
	while(!isdigit(c))
		c=getchar();
	while(isdigit(c)){
		ret=(ret<<1)+(ret<<3)+c-'0';
		c=getchar();
	}
	return ret;
}
//\sum(x_i+c-y_i)^2=\sum(x_i^2+y_i^2)+[nc^2+2c\sum(x_i-y_i)]-\sum2x_iy_i
inline void Aireen(){
	n=read();m=read();
	for(int i=0;i<n;++i) x[i]=read();
	for(int i=0;i<n;++i) y[i]=read();
	for(int i=0;i<n;++i) tot+=x[i]-y[i];
	for(int i=-m;i<=m;++i) 
		ans=min(ans,n*i*i+2*i*tot);
	tot=ans;ans=0;
	for(int i=0;i<n;++i)
		tot+=x[i]*x[i]+y[i]*y[i];
	for(int i=0;i<n;++i)
		ans+=x[i]*y[i];
	for(int i=0;i<n;++i)
		a1[i]=cp((ld)x[i],0.0),b1[i]=cp((ld)y[n-i-1],0.0),
		a2[i]=cp((ld)x[n-i-1],0.0),b2[i]=cp((ld)y[i],0.0);
	FFT::init(n);
	FFT::DFT(a1,0);FFT::DFT(b1,0);
	for(int i=0;i<FFT::n;++i)
		a1[i]=a1[i]*b1[i];
	FFT::DFT(a1,1);
	FFT::DFT(a2,0);FFT::DFT(b2,0);
	for(int i=0;i<FFT::n;++i)
		a2[i]=a2[i]*b2[i];
	FFT::DFT(a2,1);
	ans=(int)(a1[n-1].x+0.5);
	for(int i=0;i<n;++i)
		ans=max(ans,(int)(a1[i].x+a2[n-i-2].x+0.5));
	printf("%d\n",tot-(ans<<1));
}

2017-04-22 08:44:13

posted @ 2021-11-25 14:36  Aireen_Ye  阅读(21)  评论(0编辑  收藏  举报
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.