礼物
题解
多简单的一道FFT板题呀!
我们发现,增加的亮度 c c c的值为正还是为负都是没有关系的,只是对不同手环操作的问题,所以下面不会考虑 c c c的正负。
有 ∑ i = 1 n ( x i − y i + c ) 2 = ∑ i = 1 n ( x i 2 + y i 2 ) + 2 c ∑ i = 1 n ( x i − y i ) + c 2 n − 2 ∑ i = 1 n x i y i \sum_{i=1}^{n}(x_{i}-y_{i}+c)^2=\sum_{i=1}^{n}(x_{i}^2+y_{i}^2)+2c\sum_{i=1}^{n}(x_{i}-y_{i})+c^2n-2\sum_{i=1}^{n}x_{i}y_{i} ∑i=1n(xi−yi+c)2=∑i=1n(xi2+yi2)+2c∑i=1n(xi−yi)+c2n−2∑i=1nxiyi
很容易发现除了最后一个
−
2
∑
i
=
1
n
x
i
y
i
-2\sum_{i=1}^{n}x_{i}y_{i}
−2∑i=1nxiyi以外,其它的值都与
x
x
x与
y
y
y的顺序无关,可以直接求出来。
前面关于
c
c
c的式子也可以直接找对称轴求出,注意精度误差,可以枚举找到的对称轴前后两个点的值,取最小的。
可最后一个
∑
i
=
1
n
x
i
y
i
\sum_{i=1}^{n}x_{i}y_{i}
∑i=1nxiyi的最大值求着就有些麻烦了。
我们可以先将
x
x
x给倒过来,就成了
∑
i
=
1
n
a
n
−
i
+
1
y
i
\sum_{i=1}^{n}a_{n-i+1}y_{i}
∑i=1nan−i+1yi,此时两者的和是一定的,可以转化成多项式,将
y
y
y延长一倍,两个多项式相乘,第
n
+
1
n+1
n+1到
2
n
2n
2n项中系数最大的就是上式的最大值。
注意转化成多项式后应该是从
x
0
x^0
x0开始的,不是
x
1
x^1
x1。
总时间复杂度 O ( n l o g n ) O\left(nlog\, n\right) O(nlogn)。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 300005
#define reg register
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x>0?x:-x;}
template<typename _T>
inline void read(_T &x){
_T f=1;x=0;char s=getchar();
while('0'>s||'9'<s){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int n,m,rev[MAXN],lim;LL ans,suma,sumb;
struct cp{
double x,y;cp(double X=0,double Y=0){x=X;y=Y;}
inline friend cp operator + (const cp &a,const cp &b){return cp(a.x+b.x,a.y+b.y);}
inline friend cp operator - (const cp &a,const cp &b){return cp(a.x-b.x,a.y-b.y);}
inline friend cp operator * (const cp &a,const cp &b){return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
}a[MAXN],b[MAXN];
inline void fft(cp *A,int typ){
for(reg int i=0;i<lim;++i)if(i<rev[i])swap(A[i],A[rev[i]]);
for(reg int mid=1;mid<lim;mid<<=1){
const cp Wn(cos(PI/mid),typ*sin(PI/mid));
for(reg int R=mid<<1,j=0;j<lim;j+=R){
cp w(1,0);
for(int k=0;k<mid;++k,w=w*Wn){
cp x=A[j+k],y=w*A[j+mid+k];
A[j+k]=x+y;A[j+mid+k]=x-y;
}
}
}
}
signed main(){
read(n);read(m);
for(reg int i=0,x;i<n;++i)read(x),a[i].x=x,suma+=x,ans+=1ll*x*x;
for(reg int i=0,x;i<n;++i)read(x),b[i].x=x,sumb+=x,ans+=1ll*x*x;
LL x=(LL)((1.0*sumb-1.0*suma)/(2.0*n)+0.5),maxx=0,tmp=1ll*x*x*n+2ll*x*(suma-sumb);
tmp=min(1ll*(x-1LL)*(x-1LL)*n+2ll*(x-1LL)*(suma-sumb),tmp);
tmp=min(1ll*(x+1LL)*(x+1LL)*n+2ll*(x+1LL)*(suma-sumb),tmp);
reverse(a,a+n);for(reg int i=0;i<n;++i)b[i+n]=b[i];
int l=0;lim=1;while(lim<3*n)lim<<=1,++l;
for(reg int i=1;i<=lim;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<l-1);
fft(a,1);fft(b,1);for(reg int i=0;i<=lim;++i)b[i]=a[i]*b[i];fft(b,-1);
for(reg int i=0;i<=lim;++i)maxx=max(maxx,(LL)(b[i].x/lim+0.5));
printf("%lld\n",ans+tmp-2ll*maxx);
return 0;
}