先不管怎么添加,我们看看怎么样快速算出一个手环旋转n位后的差异值。
∑(xi−yi)2=∑x2i+y2i−2xiyi=Const1+Const2−2∗∑xiyi
我们只用算最后那个东西就行了。这种形式很容易想到把其中一个数组反过来,注意下标从0开始。然后就成了卷积了,即 z[k]=∑ki=0xn−1−iyi ,那么z的第n项就是没有旋转过的差异值,把y数组倍长,则第k项就是旋转了k-n位的差异值。FFT即可。
现在考虑对x加上一个数p。由于我们现在只关心差值,所以说p可以为负数,相当于给y加上-p。枚举p可能超时,那么化一下式子,看看如何。
∑(xi−yi+p)2=∑(xi−yi)2+np2+2p(∑xi−∑yi) ,这样可以发现,那些 ∑ 与p无关,所以实际上是一个二次函数,那么求出对称轴,直接加就可以了。
注意FFT的时候,逆DFT之后一定要除n····
一般来说DFT是不会错的,都是外面错了,不要乱调里面····
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef double db;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
const int N=400005;
const int mo=1004535809;
const int mo2=998244353;
const int mo3=104857601;
const int root=3;
int len,Log,ref[N],a[N],b[N],c[N],d[N],t[N],sa,sb,T,ans,w[2][N],n,m,i,invn;
int ksm(int x,int y)
{
int ret=1;
while (y)
{
if (y&1) ret=1ll*ret*x%mo;
y>>=1;
x=1ll*x*x%mo;
}
return ret;
}
int max2(int n)
{
int ret=1;
for(;ret<=n;ret*=2);
return ret*2;
}
int ci(int len){return (len==1)?0:ci(len/2)+1;}
void predo()
{
len=max2(2*n-1);
Log=ci(len);
int i,c,tp;
fo(i,0,len-1)
{
int tmp=0;
for(tp=i,c=0;c>=1,c++) tmp=(tmp<<1)+(tp&1);
ref[i]=tmp;
}
int siz=1;
fo(i,0,Log)
{
w[1][i]=ksm(root,(mo-1)/siz);
w[0][i]=ksm(w[1][i],mo-2);
siz*=2;
}
}
void dft(int *a,int n,int sig)
{
int i,j,k,W,siz,c,half,u,v;
fo(i,0,n-1) t[ref[i]]=a[i];
for(siz=2,c=1;siz<=n;siz*=2,c++)
{
half=siz/2;
W=1;
fo(i,0,half-1)
{
for(j=i;j<=n;j+=siz)
{
k=j+half;
u=t[j],v=1ll*W*t[k]%mo;
t[j]=(u+v)%mo;
t[k]=(u-v+mo)%mo;
}
W=1ll*W*w[sig][c]%mo;
}
}
fo(i,0,n-1) a[i]=t[i];
}
int solve(int add)
{
sa=sb=0;
int i;
len=max2(2*n-1);
fo(i,0,len-1) c[i]=d[i]=0;
fo(i,0,n-1) c[i]=a[n-1-i]+add,sa+=c[i]*c[i];
fo(i,0,n-1) d[i]=d[i+n]=b[i],sb+=d[i]*d[i];
Log=ci(len);
int invlen=ksm(len,mo-2);
dft(c,len,1);
dft(d,len,1);
fo(i,0,len-1) c[i]=1ll*c[i]*d[i]%mo;
dft(c,len,0);
fo(i,0,len-1) c[i]=1ll*c[i]*invlen%mo;
int ret=0;
fo(i,n-1,n*2-1)
ret=max(ret,c[i]);
return sa+sb-2*ret;
}
int main()
{
freopen("gift.in","r",stdin);
// freopen("gift.out","w",stdout);
scanf("%d %d",&n,&m);
fo(i,0,n-1) scanf("%d",a+i);
fo(i,0,n-1) scanf("%d",b+i),T+=a[i]-b[i];
predo();
ans=1e9;
ans=min(solve(-T/n),ans);
ans=min(solve(-T/n+1),ans);
ans=min(solve(-T/n-1),ans);
printf("%d\n",ans);
}