把式子拆开
$$
\sum_{i=1}^n(x_i-y_i)^2=\sum_{i=1}^nx_i^2+\sum_{i=1}^ny_i^2-2\sum_{i=1}^nx_iy_i
$$
记作$S_1$。
$$ \begin{aligned} \sum_{i=1}^n(x_i+c-y_i)^2 &=\sum_{i=1}^n(x_i+c)^2+\sum_{i=1}^ny_i^2-2\sum_{i=1}^n(x_i+c)y_i \\\ &=\sum_{i=1}^nx_i^2+n\times c^2+2c\sum_{i=1}^nx_i+\sum_{i=1}^ny_i^2-2\sum_{i=1}^nx_iy_i-2c\sum_{i=1}^n y_i \\\ &=n\times c^2 + 2c(\sum_{i=1}^nx_i-\sum_{i=1}^ny_i)+S_1 \end{aligned} $$
其中$n\times c^2 + 2c(\sum_{i=1}^nx_i-\sum_{i=1}^ny_i)$是$c$为自变量的二次函数,直接处理极值即可。
接下来考虑旋转操作。
将串$x$和$y$的所有“旋转操作”看成置换,分别记作置换群$G_x,G_y$,将计算差异值的过程看成两个置换的结果组成的新置换,其新置换复合上用来组成新置换的两个置换的任一一个置换的逆元所成的新置换可以看成“一个动,另一个不动”的匹配,因从我们只需要旋转一个序列。
对于$S_1$的影响项只有$\sum_{i=1}^nx_iy_i$,考虑令其最大。
令$f_i=y_{n-i}$,那么$S_1=\sum_{i=0}^nx_if_{n-i}$ 为序列$x_i$和$f_i$的卷积。
倍长数组$x$,构造多项式:
$$
A(z)=\sum x_iz^i,B(z)=\sum f_iz^i
$$
最优的即$\max\limits_{n\le k\le 2n}([z^k]A(z)B(z))$。
直接$\text{FFT}$即可。
#include <iostream>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <vector>
namespace poly{
const int N = 400010;
typedef std::complex<double> comp;
int rev[N]; comp c[N];
inline void change(comp f[],int len){
for (int i = 0; i < len; i++){
rev[i] = rev[i >> 1] >> 1;
if (i & 1)
rev[i] |= len >> 1;
}
for (int i = 0; i < len; i++)
if (i < rev[i]) std::swap(f[i],f[rev[i]]);
}
inline void DFT(comp f[],int len,int op){
change(f,len);
for(int h = 2; h <= len; h <<= 1){
comp wn(cos(2 * M_PI / h),sin(op * 2 * M_PI / h));
for (int j = 0; j < len; j += h){
comp cur(1,0);
for (int k = j; k < j + h / 2; k++){
comp u = f[k];
comp t = cur * f[k + h / 2];
f[k] = u + t;
f[k + h / 2] = u - t;
cur *= wn;
}
}
}
if (op == -1){
for (int i = 0; i < len; i++)
f[i] /= len;
}
}
inline std::vector<comp> mul(comp a[],comp b[],int n,int m){
std::vector<comp> res;
int limit = 1;while (limit < n + m + 1) limit <<= 1;
DFT(a,limit,1);DFT(b,limit,1);
for (int i = 0; i < limit; i++) c[i] = a[i] * b[i];
DFT(c,limit,-1);
for (int i = 0; i <= n + m; i++)
res.push_back(c[i]);
return res;
}
}
namespace wxy{
const int N = 400010;
typedef std::complex<double> comp;
int n,m,sum,a[N],b[N];
comp x[N],y[N],f[N];
std::vector<comp> c;
inline int ceil(int a,int b){
int op = 1;
if (a < 0 && b < 0){a = -1 * a; b = -1 * b;}
else{
if (a < 0){a = -1 * a; op = -1;}
if (b < 0){b = -1 * b; op = -1;}
}
if (a % b == 0) return op * (a / b);
else return op * (a / b + 1);
}
inline int floor(int a,int b){
int op = 1;
if (a < 0 && b < 0){a = -1 * a; b = -1 * b;}
else{
if (a < 0){a = -1 * a; op = -1;}
if (b < 0){b = -1 * b; op = -1;}
}
return op * (a / b);
}
inline int get(int x){return n * x * x + 2 * x * sum;}
void main(){
std::cin >> n >> m;
for (int i = 1; i <= n; i++) std::cin >> x[i];
for (int i = 1; i <= n; i++) std::cin >> y[i];
for (int i = 1; i <= n; i++){
a[i] = x[i].real(); b[i] = y[i].real();
}
int s1 = 0; sum = 0;
for (int i = 1; i <= n; i++){
s1 += a[i] * a[i]; s1 += b[i] * b[i];
sum += a[i]; sum -= b[i];
}
for (int i = 0; i < n; i++) f[i] = y[n - i];
for (int i = n + 1; i <= n * 2; i++) x[i] = x[i - n];
int maxt = 0; c = poly::mul(x,f,2 * n,n - 1);
for (int i = n; i <= 2 * n; i++) maxt = std::max(maxt,(int)(c[i].real() + 0.5));
s1 -= 2 * maxt; int ans = s1;
int delta = 0;
delta = std::min(delta,std::min(get(-1 * ceil(sum,n)),get(-1 * floor(sum,n))));
std::cout << ans + delta;
}
}signed main(){wxy::main();return 0;}
Orz