P3723 [AH2017/HNOI2017]礼物
题目
做法
定义\(r\)为增加的亮度,其实我们可以定义\(r=-m\)~\(m\),简化成对一个环处理亮度
则我们要求最小值:
\[\begin{aligned}
&\sum\limits_{i=1}^n(x_i+y_i+r)^2\\
&=\sum\limits_{i=1}^n(x_i^2+y_i^2-2x_iy_i-2y_ir+2x_ir+r^2)\\
&=(\sum\limits_{i=1}^nx_i^2+\sum\limits_{i=1}^ny_i^2)+(nr^2+2r(\sum\limits_{i=1}^na_i-\sum\limits_{i=1}^nb_i))-2\sum\limits_{i=1}^nx_iy_i
\end{aligned}\]
其中左部分\(O(n)\),中间枚举\(O(m)\)
右部分\(\sum\limits_{i=1}^nx_iy_i\),\(x\)数组翻转一下,就成了卷积形式,然后再复制一倍,FFT后,\(A_{n+1}\)~\(A_{2n}\)就是不同的对接环形式,然后暴力枚举\(r\)
时间复杂度\(O(3nlog(3n)+nm)\)
My complete code
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
#include<ctime>
#include<cmath>
#include<vector>
using namespace std;
typedef int LL;
inline LL Read(){
LL x(0),f(1);char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*f;
}
const LL maxn=1e6,inf=0x3f3f3f3f;
const double Pi=acos(-1.0);
struct complex{
double x,y;
complex (double xx=0,double yy=0){x=xx,y=yy;}
}A[maxn],B[maxn];
LL n,m,a1,b1,a2,b2,limit,L,N,ans;
LL a[maxn],b[maxn],c[maxn],R[maxn];
complex operator -(complex x,complex y){
return complex(x.x-y.x,x.y-y.y);
}
complex operator +(complex x,complex y){
return complex(x.x+y.x,x.y+y.y);
}
complex operator *(complex x,complex y){
return complex(x.x*y.x-x.y*y.y,x.x*y.y+x.y*y.x);
}
inline void FFT(complex *A,LL type){
for(LL i=0;i<limit;++i)
if(i<R[i])
swap(A[i],A[R[i]]);
for(int mid=1;mid<limit;mid<<=1){
complex WN(cos(Pi/mid),type*sin(Pi/mid));
for(int R=mid<<1,j=0;j<limit;j+=R){
complex w(1,0);
for(int k=0;k<mid;++k,w=w*WN){
complex x=A[j+k],y=w*A[j+mid+k];
A[j+k]=x+y,
A[j+mid+k]=x-y;
}
}
}
}
int main(){
n=Read(),m=Read();
for(LL i=1;i<=n;++i)
a[i]=Read(),a1+=a[i]*a[i],a2+=a[i];
for(LL i=1;i<=n;++i)
b[i]=Read(),b1+=b[i]*b[i],b2+=b[i];
for(LL i=1;i<=n;++i)
c[i]=a[n-i+1],c[n+i]=c[i];
N=3*n;
limit=1,L=0;
while(limit<N)
limit<<=1,++L;
for(LL i=0;i<limit;++i)
A[i]=complex(1.0*c[i],0.0);
for(LL i=0;i<limit;++i)
B[i]=complex(1.0*b[i],0.0);
for(LL i=0;i<limit;++i)
R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
FFT(A,1),FFT(B,1);
for(LL i=0;i<limit;++i)
A[i]=A[i]*B[i];
FFT(A,-1); ans=inf;
for(LL i=1;i<=n;++i)
for(LL j=-m;j<=m;++j)
ans=min(ans,a1+b1+(j*j*n+2*j*(a2-b2))-2*(LL)(A[i+n].x/limit+0.5));
printf("%d\n",ans);
return 0;
}