题目大意:给你两串项链,长度为n,每条分别有恰好k个黑色珠子。定义两个点距离
d
i
s
(
x
,
y
)
=
[
m
i
n
(
∣
x
−
y
∣
,
n
−
∣
x
−
y
∣
)
]
2
dis(x,y)=\left[min\left(|x-y|,n-|x-y|\right)\right]^2
dis(x,y)=[min(∣x−y∣,n−∣x−y∣)]2。你可以旋转其中一串项链任意整数单位距离,然后要找到一个排列p,使得
∑
i
=
1
k
d
i
s
(
x
i
,
y
p
i
)
\sum_{i=1}^k dis(x_i,y_{p_i})
∑i=1kdis(xi,ypi)最小。其中
x
i
,
y
i
x_i,y_i
xi,yi表示两个串第i个黑珠子的位置。
题解:关于那个距离,先令
y
i
+
k
=
y
i
+
n
y_{i+k}=y_i+n
yi+k=yi+n倍长,然后问题转为求:
min
s
∈
[
0
,
k
)
,
c
∈
[
0
,
n
)
F
(
s
,
c
)
=
∑
i
=
0
k
−
1
(
x
i
−
y
i
+
s
+
c
)
2
\min_{s\in[0,k),c\in[0,n)}F(s,c)=\sum_{i=0}^{k-1}(x_i-y_{i+s}+c)^2
s∈[0,k),c∈[0,n)minF(s,c)=i=0∑k−1(xi−yi+s+c)2
关于后面的那个
F
(
s
,
c
)
F(s,c)
F(s,c),展开后将c视为未知数,使用FFT将其各项系数求出,再取c为对称轴即可。
注意本题要求c必须是整数,所以需要取整后晃荡一下。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lint long long
#define N 4010
#define db double
#define gc getchar()
using namespace std;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const db PI=acos(-1);
struct E{
db x,y;E(db _x=0,db _y=0) { x=_x,y=_y; }
inline E& operator=(const E &w) { return x=w.x,y=w.y,*this; }
inline E operator+(const E &w)const{ return E(x+w.x,y+w.y); }
inline E operator-(const E &w)const{ return E(x-w.x,y-w.y); }
inline E operator*(const E &w)const{ return E(x*w.x-y*w.y,x*w.y+y*w.x); }
inline E& operator+=(const E &w) { return x+=w.x,y+=w.y,*this; }
inline E& operator-=(const E &w) { return x-=w.x,y-=w.y,*this; }
inline E& operator*=(const E &w) { return (*this)=(*this)*w; }
}a[N<<3],b[N<<3];int x[N],y[N<<1],r[N<<3];lint sy[N<<1],sy2[N<<1],f[N<<2];
lint S(lint *s,int l,int r) { return s[r]-(l?s[l-1]:0); }
inline int FFT(E *a,int n,int s)
{
for(int i=1;i<n;i++) if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=1;i<n;i<<=1)
{
E wn(cos(PI/i),s*sin(PI/i));
for(int j=0,t=i<<1;j<n;j+=t)
{
E w(1,0);
for(int k=0;k<i;k++,w*=wn)
{
E x=a[j+k],y=w*a[j+k+i];
a[j+k]=x+y,a[j+k+i]=x-y;
}
}
}
if(s<0) for(int i=0;i<n;i++) a[i].x/=n,a[i].y/=n;
return 0;
}
inline int tms(int *A,int *B,lint *C,int m1,int m2)
{
int n=1,L=0;while(n<m1+m2-1) n<<=1,L++;
for(int i=1;i<n;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
for(int i=0;i<m1;i++) a[i]=E(A[i],0);
for(int i=m1;i<n;i++) a[i]=E(0,0);FFT(a,n,1);
for(int i=0;i<m2;i++) b[i]=E(B[i],0);
for(int i=m2;i<n;i++) b[i]=E(0,0);FFT(b,n,1);
for(int i=0;i<n;i++) a[i]*=b[i];FFT(a,n,-1);
for(int i=0;i<m1+m2-1;i++) C[i]=(lint)(a[i].x+0.5);
return 0;
}
int main()
{
for(int T=inn();T;T--)
{
int n=inn(),k=inn();lint ans=LLONG_MAX,sx=0,sx2=0;
for(int i=0;i<k;i++) x[i]=inn(),sx+=x[i],sx2+=x[i]*x[i];
for(int i=0;i<k;i++) y[i]=inn(),y[i+k]=y[i]+n;
for(int i=0;i<k/2;i++) swap(x[i],x[k-i-1]);
tms(x,y,f,k,2*k-1);
for(int i=0;i<k;i++) f[i]=f[i+k-1];
sy[0]=y[0],sy2[0]=y[0]*y[0];
for(int i=1;i<2*k;i++)
sy[i]=sy[i-1]+y[i],sy2[i]=sy2[i-1]+y[i]*y[i];
for(int i=0;i<k;i++)
{
lint s=2*(sx-S(sy,i,k-1+i)),s2=sx2+S(sy2,i,k-1+i);
lint c=(lint)(-(db)s/(2*k)+0.5);
ans=min(ans,k*c*c+s*c-2*f[i]+s2);
c+=1,ans=min(ans,k*c*c+s*c-2*f[i]+s2);
c-=2,ans=min(ans,k*c*c+s*c-2*f[i]+s2);
}
printf("%lld\n",ans);
}
return 0;
}