分析:
求
∑ni=1(xi−yi)2
∑
i
=
1
n
(
x
i
−
y
i
)
2
假设我们旋转了 j j 位,每一位上加,则有式子
∑ni=1(xi+j+c−yi)2 ∑ i = 1 n ( x i + j + c − y i ) 2
=∑ni=1x2i+j+y2i+c2+2xi+jc−2yic−2xi+jyi = ∑ i = 1 n x i + j 2 + y i 2 + c 2 + 2 x i + j c − 2 y i c − 2 x i + j y i
=∑x2i+∑y2i+nc2+2c∑(xi−yi)−2∑xi+jyi = ∑ x i 2 + ∑ y i 2 + n c 2 + 2 c ∑ ( x i − y i ) − 2 ∑ x i + j y i
上式中只有 xi+jyi x i + j y i 需要计算
受这道题的启发
我们可以把
y
y
串翻转,变成一个卷积的形式
又因为有一个循环的形式,我们把x串加倍即可
最后枚举c分别计算上式即可
Q.
为什么卷积可以完成这个任务呢
A.
我们看一个例子:
y:d,e,f
y
:
d
,
e
,
f
如分析,首先我们把x加倍,变成环的形式:
x:a,b,c,a,b,c
x
:
a
,
b
,
c
,
a
,
b
,
c
把y翻转,方便卷积:
y:f,e,d
y
:
f
,
e
,
d
x: a b c a b c
y: f e d
//------------------------------------
da db dc da db dc
ea eb ec ea eb ec
fa fb fc fa fb fc
* * * *
看一下标出来的几位,就是题目所求啦
GXZlegend大大表示,
c
c
不用枚举!
f′=∑ni=1(xi+c−yi)2
f
′
=
∑
i
=
1
n
(
x
i
+
c
−
y
i
)
2
f′−f=∑ni=1(2xic−2yic+c2)=c∗∑2xi−2yi+c
f
′
−
f
=
∑
i
=
1
n
(
2
x
i
c
−
2
y
i
c
+
c
2
)
=
c
∗
∑
2
x
i
−
2
y
i
+
c
c=∑yi−∑xin c = ∑ y i − ∑ x i n
也就是说无论如何旋转,c的最优值总是固定的 ∑yi−∑xin ∑ y i − ∑ x i n (四舍五入到整数)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#define ll long long
using namespace std;
const int N=200010;
const int INF=1e9;
const double Pi=acos(-1.0);
struct node{
double x,y;
node (double xx=0,double yy=0) {
x=xx;y=yy;
}
};
node a[N],b[N],o[N],_o[N];
node operator +(const node &a,const node &b) {return node(a.x+b.x,a.y+b.y);}
node operator -(const node &a,const node &b) {return node(a.x-b.x,a.y-b.y);}
node operator *(const node &a,const node &b) {return node(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
int Sx2=0,Sy2=0,S=0,x[N],y[N],c,f[N];
int n,m,fn;
void init(int n) {
for (int i=0;i<=n;i++) {
o[i]=node(cos(2.0*Pi*i/n),sin(2.0*Pi*i/n));
_o[i]=node(cos(2.0*Pi*i/n),-sin(2.0*Pi*i/n));
}
}
void FFT(int n,node *a,node *w) {
int i,j=0,k;
for (i=0;i<n;i++) {
if (i>j) swap(a[i],a[j]);
for (int l=n>>1;(j^=l)<l;l>>=1);
}
for (i=2;i<=n;i<<=1) {
int m=i>>1;
for (j=0;j<n;j+=i)
for (k=0;k<m;k++) {
node z=a[j+m+k]*w[n/i*k];
a[j+k+m]=a[j+k]-z;
a[j+k]=a[j+k]+z;
}
}
}
int main()
{
c=0;
scanf("%d%d",&n,&m);
for (int i=0;i<n;i++) {
scanf("%d",&x[i]);
Sx2+=x[i]*x[i]; //sum x^2
S+=2*x[i]; //sum 2(x-y)
}
for (int i=0;i<n;i++) {
scanf("%d",&y[i]);
Sy2+=y[i]*y[i]; //sum y^2
S-=2*y[i];
}
fn=1;
while (fn<=n+n) fn<<=1;
init(fn);
for (int i=0;i<n*2;i++) a[i]=node(x[i%n],0); //加倍环变序列
for (int i=0;i<n;i++) b[i]=node(y[n-i-1],0); //翻转
FFT(fn,a,o); FFT(fn,b,o);
for (int i=0;i<=fn;i++) a[i]=a[i]*b[i];
FFT(fn,a,_o);
for (int i=0;i<=fn;i++) f[i]=(int)(a[i].x/(double)fn+0.5);
int ans=INF;
for (c=-m;c<=m;c++)
for (int i=n;i<2*n;i++)
ans=min(ans,Sx2+Sy2+c*S+n*c*c-2*f[i]);
printf("%d",ans);
return 0;
}