[HNOI2017] 礼物

可以发现,(ai+t)-bi和ai-(bi+t)可以表示为ai-bi+x(x in [-m,m])。

对于一对: (ai+x-bi)2==ai2+bi^2+x2+2(ai-bi)x-2aibi
再求和 sum (ai+x-bi)2=sum(ai2)+sum(bi2)+nx2+2x(sum(ai)-sum(bi))-2sum(aibi)

观察,在x一定的情形之下,要这个和尽量小,就要最大化sum(aibi)。

令ci=a[n-i+1], 倍长c(变旋转为滑动),sum(aibi)=sum(c[n-i+1]bi),可以利用卷积的形式:如令C(x)=sum(ci(x^i)), B(x)=sum(bi(x^i)),令D(x)=C(x)B(x),
可知,D(x)的n+p次方项的系数为sum(c[n-i+p]*bi)=sum(a[i+1-p]bi)(a[-n+1,...,0]=a[1,n]),找到D(x)的n+p次方项的系数的最大值。

计算卷积时套上FFT。

#include <bits/stdc++.h>
using namespace std;

const int N=2e5+10;
const double Pi=acos(-1);

struct cplx {
	double x,y;
	cplx(double x=0,double y=0):x(x),y(y){}
	cplx operator+(const cplx& d) {return cplx(x+d.x,y+d.y);}
	cplx operator-(const cplx& d) {return cplx(x-d.x,y-d.y);}
	cplx operator*(const cplx& d) {return cplx(x*d.x-y*d.y,x*d.y+y*d.x);}
} A[N],B[N];

int lmt,l,r[N];

void fastFourierTrans(cplx*a,int type) {
	for(int i=0; i<lmt; ++i) if(i<r[i]) swap(a[i],a[r[i]]);
	for(int k=1; k<lmt; k<<=1) {
		for(int i=0; i<lmt; i+=(k<<1)) {
			cplx e(1,0), d(cos(Pi/k),type*sin(Pi/k));
			for(int j=0; j<k; j++, e=e*d) {
				cplx t=e*a[i+j+k];
				a[i+j+k]=a[i+j]-t;
				a[i+j]  =a[i+j]+t;
			}
		}
	} 
}

int n,m;
double a[N],b[N],c[N];
double sqs,sco,dif,ans=1e15;

int main() {
	scanf("%d%d",&n,&m);
	for(int i=1; i<=n; ++i) scanf("%lf",a+i);
	for(int i=1; i<=n; ++i) scanf("%lf",b+i);
	for(int i=1; i<=n; ++i) c[i]=c[n+i]=a[n-i+1];
	for(int i=1; i<=n+n; ++i) A[i].x=c[i], B[i].x=b[i];
	for(lmt=1,l=0; lmt<(n<<1); lmt<<=1,l++);
	for(int i=0; i<lmt; ++i) r[i]=r[i>>1]>>1|((i&1)<<(l-1));
	fastFourierTrans(A,1);
	fastFourierTrans(B,1);
	for(int i=0; i<lmt; ++i) A[i]=A[i]*B[i];
	fastFourierTrans(A,-1);
	for(int i=0; i<lmt; ++i) A[i].x=floor(A[i].x/lmt+0.5);
	for(int i=1; i<=n; ++i) {
		sqs+=a[i]*a[i]+b[i]*b[i]; 
		sco+=2*(a[i]-b[i]);
		dif=max(dif,A[n+i].x);
	}
	for(int i=-m; i<=m; ++i) {
		ans=min(ans,sqs+n*i*i+sco*i-2*dif);
	}
	printf("%.0f\n",ans);
	return 0;
}

忘掉\(\LaTeX\)吧。。

posted @ 2018-12-27 14:50  nosta  阅读(99)  评论(0编辑  收藏  举报