[bzoj 4827][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\)麻烦你帮他计算一下,进行调整(亮度改造和旋转),使得两个手环之间的差异值最小, 这个最小值是多少呢?
Solution
可以看成是A手环的增加量为\(a\),其中\(a\)可以是负数,显然\(-m \leq a \leq m\)。
\[ans=min(\sum_{i=1}^{n} (x_i+a-y_i)^2) \]\[ans=min(\sum_{i=1}^{n}({x_i}^2+{y_i}^2)+2na+2a\sum_{i=1}^{n}(x_i-y_i)-2\sum_{i=1}^{n}x_iy_i) \]\(a\)的取值可以直接枚举,只需要算出\(\max(\sum_{i=1}^{n}x_iy_i)\)。
把\(x\)序列翻转,这样就是求\(\max(\sum_{i=1}^{n}x_{n-i+1}y_i)\)了,考虑把翻转后的序列再倍长,直接用\(FFT\)求卷积
最后在\([n+1,n*2]\)上找最大值即可。
Code
#include<bits/stdc++.h>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
#define MN 2097152
const double Pi=std::acos(-1.);
struct complex
{
double x,y;
complex(double _x=0,double _y=0):x(_x),y(_y){}
inline complex operator+(const complex& o)const{return complex(x+o.x,y+o.y);}
inline complex operator-(const complex& o)const{return complex(x-o.x,y-o.y);}
inline complex operator*(const complex& o)const{return complex(x*o.x-y*o.y,x*o.y+y*o.x);}
inline void swap(complex& o){complex t=o;o=(*this);*this=t;}
}a[MN],b[MN];
int N,di,pos[MN];
inline void FFT(complex *a,int type)
{
register int i,j,p,k;
for(i=0;i<N;++i)if(i<pos[i])a[i].swap(a[pos[i]]);
for(i=1;i<N;i<<=1)
{
complex wn(cos(Pi/i),type*sin(Pi/i));
for(p=i<<1,j=0;j<N;j+=p)
{
complex w(1,0);
for(k=0;k<i;++k,w=w*wn)
{
complex X=a[j+k],Y=w*a[j+i+k];
a[j+k]=X+Y;a[j+i+k]=X-Y;
}
}
}
}
ll sum,s,ans=5e9;
ll sqr(ll x){return x*x;}
int main()
{
register int n,m,i,j;
n=read();m=read();
for(i=1;i<=n;++i) a[n-i+1].x=a[n*2-i+1].x=read(),sum+=sqr(a[n-i+1].x),s+=a[n-i+1].x*2;
for(i=1;i<=n;++i) b[i].x=read(),sum+=sqr(b[i].x),s-=b[i].x*2;
for(N=1;N<=n*3;N<<=1,di++);
for(i=0;i<N;++i) pos[i]=(pos[i>>1]>>1)|((i&1)<<(di-1));
FFT(a,1);FFT(b,1);
for(i=0;i<N;++i) a[i]=a[i]*b[i];
FFT(a,-1);
for(i=0;i<=n*3;++i) a[i].x=(int)(a[i].x/N+.5);
for(i=1;i<=n;++i)for(j=-m;j<=m;++j) ans=min(ans,sum+1ll*n*sqr(j)+1ll*j*s-2ll*(int)a[n+i].x);
return 0*printf("%lld\n",ans);
}
Blog来自PaperCloud,未经允许,请勿转载,TKS!