【Hnoi2017】礼物
题目描述
我的室友最近喜欢上了一个可爱的小女生。马上就要到她的生日了,他决定买一对情侣手环,一个留给自己,一个送给她。每个手环上各有\(n\)个装饰物,并且每个装饰物都有一定的亮度。
但是在她生日的前一天,我的室友突然发现他好像拿错了一个手环,而且已经没时间去更换它了!他只能使用一种特殊的方法,将其中一个手环中所有装饰物的亮度增加一个相同的自然数\(c\)(即非负整数)。并且由于这个手环是一个圆,可以以任意的角度旋转它,但是由于上面 装饰物的方向是固定的,所以手环不能翻转。需要在经过亮度改造和旋转之后,使得两个手环的差异值最小。
在将两个手环旋转且装饰物对齐了之后,从对齐的某个位置开始逆时针方向对装饰物编号\(1,2,…,n\),其中\(n\)为每个手环的装饰物个数,第\(1\)个手环的\(i\)号位置装饰物亮度为\(x_i\),第\(2\)个手环的\(i\)号位置装饰物亮度为\(y_i\),两个手环之间的差异值为(参见输入输出样例和样例解释): $$\sum_{i=1}{n}(x_i-y_i)2$$麻烦你帮他计算一下,进行调整(亮度改造和旋转),使得两个手环之间的差异值最小,这个最小值是多少呢?
输入
输入数据的第一行有两个数\(n\),\(m\),代表每条手环的装饰物的数量为\(n\),每个装饰物的初始亮度小于等于\(m\)。
接下来两行,每行各有\(n\)个数,分别代表第一条手环和第二条手环上从某个位置开始逆时针方向上各装饰物的亮度。
输出
输出一个数,表示两个手环能产生的最小差异值。注意在将手环改造之后,装饰物的亮度可以大于\(m\)。
数据范围
100%的数据保证\(1≤n≤50000,1≤m≤100,1≤ai≤m\)
显然是要计算\(\sum_{i=1}^{n}(x_i-y_{i+x}+y)^2\)的最小值,其中\(0≤x<n\),\(y\)任意
展开这个式子,$$\sum_{i=1}{n}(x_i-y_{i+x}+y)2$$
除了\(2*\sum_{i=1}^{n}x_iy_{i+x}\),其他的和\(x_i\)与\(y_i\)相关的项都可以在\(O(n)\)的时间内算出了
那么\(2y*\sum_{i=1}^{n}(x_i-y_i)+y^2\)配个方,就可以求出最小值了,而\(\sum_{i=1}^{n}(x_i^2-y_{i}^2)\)是固定的
现在的问题就是求\(2*\sum_{i=1}^{n}x_iy_{i+x}\),我们可以用FFT来解决
设\(x'_i=x_{n-i+1}\),那么\(2*\sum_{i=1}^{n}x_iy_{i+x}=2*\sum_{i=1}^{n}x'_{n-i+1}y_{i+x}\),这样就可以用FFT算出来了
总的时间复杂度\(O(nlogn)\)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<string>
#include<climits>
#include<vector>
#include<cmath>
#include<map>
#include<set>
#include<complex>
#define LL long long
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x){
char c=nc();int b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
inline void read(LL &x){
char c=nc();LL b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
inline int read(char *s)
{
char c=nc();int len=0;
for(;!(c>='A' && c<='Z');c=nc()) if (c==EOF) return 0;
for(;(c>='A' && c<='Z');s[len++]=c,c=nc());
s[len++]='\0';
return len;
}
inline void read(char &x){
for (x=nc();!(x>='A' && x<='Z');x=nc());
}
int wt,ss[19];
inline void print(int x){
if (x<0) x=-x,putchar('-');
if (!x) putchar(48); else {
for (wt=0;x;ss[++wt]=x%10,x/=10);
for (;wt;putchar(ss[wt]+48),wt--);}
}
inline void print(LL x){
if (x<0) x=-x,putchar('-');
if (!x) putchar(48); else {for (wt=0;x;ss[++wt]=x%10,x/=10);for (;wt;putchar(ss[wt]+48),wt--);}
}
#define pi acos(-1)
#define E complex<double>
E a[500010],b[500010];
int n,m,x,f[50010],u[50010],v[50010];
void fft(E *x,int n,int tp)
{
if (n==1) return;
E l[n>>1],r[n>>1];
for (int i=0;i<n;i+=2)
l[i>>1]=x[i],r[i>>1]=x[i+1];
fft(l,n>>1,tp),fft(r,n>>1,tp);
E w(1,0),wn(cos(pi*2/n),sin(pi*2/n*tp)),t;
for (int i=0;i<n>>1;i++,w*=wn)
t=r[i]*w,x[i]=l[i]+t,x[i+(n>>1)]=l[i]-t;
}
int main()
{
read(n);read(m);
int x,N=n;
for (int i=0;i<n;i++)
read(x),u[i]=x,a[n-i-1]=x;
for (int i=0;i<n;i++)
read(x),b[i]=x,v[i]=x;
for (int i=0;i<n;i++)
b[i+n]=b[i];
m=n*4;
for (n=1;n<=m;n<<=1);
fft(a,n,1);fft(b,n,1);
for (int i=0;i<=n;i++)
a[i]*=b[i];
fft(a,n,-1);
int Max=0;
for (int i=0;i<N;i++)
Max=max(Max,(int)(a[N+i-1].real()/n+0.5));
int ans=0;
for (int i=0;i<N;i++)
ans+=u[i]*u[i]+v[i]*v[i];
ans=ans-Max*2;
x=N;int y=0;
for (int i=0;i<N;i++)
y+=u[i]-v[i];
y=y*2;
int z=(-y)/(2*x);
Max=z*z*x+y*z;
z+=1,Max=min(Max,z*z*x+y*z);
z-=2,Max=min(Max,z*z*x+y*z);
ans+=Max;
print(ans),puts("");
return 0;
}