Description
给定长度为n的两个在环上的序列x[]和y[],求一种配对方式使得
最小,输出最小值
1≤n≤50000, 1≤m≤100, 1≤ai≤m
Solution
循环的问题复制一份就好了,差一下柿子可以发现其实就是
其中两个平方项可以预处理,中间那一坨可以把y倒过来FFT,带C的柿子可以枚举C求最小值
就酱
Code
#include <stdio.h>
#include <string.h>
#include <complex>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef std:: complex <double> com;
const double pi=3.14159265358;
const int INF=0x3f3f3f3f;
const int N=320005;
com c[N],d[N];
int rev[N],a[N],b[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void FFT(com *a,int len,int f) {
for (int i=0;i<len;i++) if (i<rev[i]) std:: swap(a[i],a[rev[i]]);
for (int i=1;i<len;i*=2) {
com wn(cos(pi/i),sin(pi/i)*f);
for (int j=0;j<len;j+=i*2) {
com w(1,0);
for (int k=0;k<i;k++) {
com u=a[j+k],v=a[j+k+i]*w;
a[j+k]=u+v; a[j+k+i]=u-v;
w*=wn;
}
}
}
if (f==-1) for (int i=0;i<len;i++) a[i]/=len;
}
int main(void) {
int n=read(),m=read(),sumb=0;
for (int i=1;i<=n;i++) a[i+n]=a[i]=read();
for (int i=1;i<=n;i++) sumb+=(b[n-i+1]=read());
int len,lg; for (len=1,lg=0;len<=n*2;len*=2,lg++);
for (int i=0;i<len;i++) rev[i]=(rev[i/2]/2)|((i&1)<<(lg-1));
for (int i=0;i<len;i++) c[i]=a[i+1],d[i]=b[i+1];
FFT(c,len,1); FFT(d,len,1);
for (int i=0;i<len;i++) c[i]*=d[i];
FFT(c,len,-1);
int ans=INF;
for (int C=-m,sum=0;C<=m;C++,sum=0) {
for (int i=1;i<=n;i++) sum+=(a[i]+C)*(a[i]+C)+b[i]*b[i];
for (int i=n;i<2*n;i++) {
ans=std:: min(ans,sum-2*(int)(c[i].real()+0.1)-2*C*sumb);
}
}
printf("%d\n", ans);
return 0;
}