luogu P3723 [AH2017/HNOI2017]礼物

背景:

最近一直在补坑。

题意:

有两个序列 a , b a,b (围成两个圈),将 a a 序列所有的值加上一个非负整数 c c (自己给的),将 b b 序列逆时针旋转一定的角度,求 i = 1 n ( a i b i ) 2 \sum\limits_{i=1}^{n}(a_i-b_i)^2 的最小值。

思路:

不妨假设旋转完的 b b 序列为 b b' 。,则题目就是求 i = 1 n ( a i + c b i ) 2 \sum\limits_{i=1}^{n}(a_i+c-b'_i)^2 的最小值。
考虑化简式子。
i = 1 n ( a i + c b i ) 2 \sum\limits_{i=1}^{n}(a_i+c-b'_i)^2
拆括号,得:
i = 1 n ( a i 2 + c 2 + b i 2 + 2 a i c 2 a i b i 2 c b i ) \sum\limits_{i=1}^{n}(a_i^2+c^2+{b'_i}^2+2*a_i*c-2*a_i*b'_i-2*c*b'_i)
发现 a i 2 + b i 2 a_i^2+{b'_i}^2 为定值,将其提出。
i = 1 n ( a i 2 + b i 2 ) + i = 1 n ( c 2 + 2 a i c 2 a i b i 2 c b i ) \sum\limits_{i=1}^{n}(a_i^2+{b'_i}^2)+\sum\limits_{i=1}^{n}(c^2+2*a_i*c-2*a_i*b'_i-2*c*b'_i)
再提取一个 2 c 2*c 得:
i = 1 n ( a i 2 + b i 2 ) + i = 1 n ( c 2 + 2 c ( a i b i ) ) i = 1 n ( 2 a i b i ) \sum\limits_{i=1}^{n}(a_i^2+{b'_i}^2)+\sum\limits_{i=1}^{n}(c^2+2*c*(a_i-b'_i))-\sum\limits_{i=1}^{n}(2*a_i*b'_i)
提取出一些数,得到:
i = 1 n ( a i 2 ) + i = 1 n ( b i 2 ) + n c 2 + 2 c ( i = 1 n a i i = 1 n b i ) i = 1 n ( 2 a i b i ) \sum\limits_{i=1}^{n}(a_i^2)+\sum\limits_{i=1}^{n}({b'_i}^2)+n*c^2+2*c*(\sum\limits_{i=1}^{n}a_i-\sum\limits_{i=1}^{n}b'_i)-\sum\limits_{i=1}^{n}(2*a_i*b'_i)
c c 的问题比较容易搞定,因为它与最后一个因式无关。那么发现只有 i = 1 n ( 2 a i b i ) -\sum\limits_{i=1}^{n}(2*a_i*b'_i) 为不定值,使 i = 1 n ( 2 a i b i ) -\sum\limits_{i=1}^{n}(2*a_i*b'_i) 的值最小即可。

考虑构造 b b' 使得其最小,不妨使 a i a'_i 为原 a a 序列及其反向倍长序列。那么再使 b b'' b b 的反向序列,此时形成了一个卷积的形式,那么答案一定就为可取的数中的最大值(前面有一个 - 号)。

最后再套入上式求解即可。

代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const double pai=acos(-1.0);
struct comp
{
	double x,y;
	comp(double xx=0,double yy=0):x(xx),y(yy) {}
	friend comp operator+(const comp &x,const comp &y) {return comp(x.x+y.x,x.y+y.y);}
	friend comp operator-(const comp &x,const comp &y) {return comp(x.x-y.x,x.y-y.y);}
	friend comp operator*(const comp &a,const comp &b) {return comp(a.x*b.x-a.y*b.y,a.x*b.y+b.x*a.y);}
}a[500000],b[500000];
	int n,m,limit=1,l=0;
	int r[500000];
	LL as1=0,as2=0,bs1=0,bs2=0,ans=2147483647;
void FFT(comp *now,int ty)
{
	for(int i=0;i<limit;i++)
		if(i<r[i]) swap(now[i],now[r[i]]);
	for(int mid=1;mid<limit;mid<<=1)
	{
		comp wn(cos(pai/mid),ty*sin(pai/mid));
		for(int j=0,R=(mid<<1);j<limit;j+=R)
		{
			comp w(1,0);
			for(int k=0;k<mid;k++,w=w*wn)
			{
				comp x=now[j+k],y=w*now[j+k+mid];
				now[j+k]=x+y;
				now[j+k+mid]=x-y;
			}
		}
	}
}
	int d1[50010],d2[50010];
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&d1[i]);
		as1+=(LL)d1[i];
		as2+=(LL)d1[i]*d1[i];
	}
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&d2[i]);
		bs1+=(LL)d2[i];
		bs2+=(LL)d2[i]*d2[i];
	}
	while(limit<=(n*3))
		limit<<=1,l++;
	for(int i=1;i<=limit;i++)
		r[i]=((r[i>>1]>>1)|((i&1)<<(l-1)));
	for(int i=1;i<=n;i++)
	{
		a[i].x=a[i+n].x=(double)d1[i];
		b[i].x=(double)d2[n-i+1];
	}
	FFT(a,1);
	FFT(b,1);
	for(int i=0;i<=limit;i++)
		a[i]=a[i]*b[i];
	FFT(a,-1);
	for(int i=1;i<=n;i++)
		for(int j=-m;j<=m;j++)
			ans=min(ans,as2+bs2+j*j*n+(LL)2*j*(as1-bs1)-(LL)2*(LL)(a[i+n].x/limit+0.5));
	printf("%lld",ans);
}

猜你喜欢

转载自blog.csdn.net/zsyz_ZZY/article/details/84971416