[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