(摸肚皮)真的真的真的真的扯不动了。
答案长这样:$\sum\limits(x-y+c)^2$
拆一下式子:$\sum\limits x^2-2xy+y^2+c^2+2cx-2cy$
把带$c$的提出来:$nc^2+2c(\sum x-\sum y)$
这不一二次函数吗?由于两个手环都可以加$c$,所以$c$实际上可以取任意整数。
考虑到精度问题,$c$为整数,而且$m\le 100$,直接$O(m)$枚举求最小值都行。
然后带$c$的成了常数项,$x^2+y^2$也是常数项,就剩了个$-\sum 2xy$
把$y$序列翻转后面补$0$,$x$序列拷贝一份接到后面,这个式子就成了$-2\sum\limits_{j=0}^i x_jy_{i-j}$
$NTT$卷起来就完了。
代码:
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #define maxn 135005 #define inf 0x3f3f3f3f const int mod = 998244353; const int g = 3; using namespace std; inline int read(){ int x=0,y=0; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return y?-x:x; } inline int quickpow(int x,int y=mod-2){ int ans=1; while(y){ if(y&1)ans=1ll*ans*x%mod; x=1ll*x*x%mod,y>>=1; } return ans; } const int ig = quickpow(g); int a[maxn],b[maxn],rev[maxn]; inline int mix(int x,int y){return x+y>=mod?x+y-mod:x+y;} void NTT(int *f,int n,bool type){ for(register int i=0;i<n;++i)if(i<rev[i])swap(f[i],f[rev[i]]); for(register int p=2;p<=n;p<<=1){ int len=p>>1,o=quickpow(type?ig:g,(mod-1)/p); for(register int i=0;i<n;i+=p){ int gen=1,cop; for(register int j=i;j<i+len;++j){ cop=1ll*f[j+len]*gen%mod; f[j+len]=mix(f[j],mod-cop),f[j]=mix(f[j],cop),gen=1ll*gen*o%mod; } } } if(type){ int inv=quickpow(n); for(register int i=0;i<n;++i)a[i]=1ll*a[i]*inv%mod; } } int main(){ int n=read(),m=read(),sum=0,base=0,mi=inf,lim=1,ans=0; for(register int i=0;i<n;++i)a[i]=a[i+n]=read(); for(register int i=0;i<n;++i)b[i]=read(),sum+=a[i]-b[i],base+=a[i]*a[i]+b[i]*b[i]; sum<<=1,reverse(b,b+n); for(register int i=-m;i<=m;++i)mi=min(mi,n*i*i+sum*i); base+=mi; while(lim<=n<<1)lim<<=1; for(register int i=0;i<lim;++i)rev[i]=(rev[i>>1]>>1)|(i&1?lim>>1:0); NTT(a,lim,0),NTT(b,lim,0); for(register int i=0;i<lim;++i)a[i]=1ll*a[i]*b[i]%mod; NTT(a,lim,1); for(register int i=n-1;i<(n<<1)-1;++i)ans=max(ans,a[i]<<1); printf("%d\n",base-ans); }