题意
可以将 x i x_i xi加上任意数字 c c c,并任意旋转一手环,使得 ∑ i = 1 n ( x i − y i ) 2 \sum_{i=1}^n(x_i-y_i)^2 ∑i=1n(xi−yi)2最小
分析
先不考虑旋转:
∑
i
=
1
n
(
x
i
−
y
i
)
2
\sum_{i=1}^{n}(x_i-y_i)^2
∑i=1n(xi−yi)2
∑ i = 1 n ( x i + c − y i ) 2 \sum_{i=1}^{n}(x_i+c-y_i)^2 ∑i=1n(xi+c−yi)2最小
= ∑ i = 1 n ( x i 2 + y i 2 + 2 c ( x i − y i ) − 2 x i y i + c 2 ) =\sum_{i=1}^n(x_i^2+y_i^2+2c(x_i-y_i)-2x_iy_i+c^2) =∑i=1n(xi2+yi2+2c(xi−yi)−2xiyi+c2)
= ∑ i = 1 n x i 2 + ∑ i = 1 n y i 2 + 2 c ∑ i = 1 n x i − 2 c ∑ i = 1 n y i − 2 ∑ i = 1 n x i y i + n c 2 =\sum_{i=1}^nx_i^2+\sum_{i=1}^ny_i^2+2c\sum_{i=1}^nx_i-2c\sum_{i=1}^ny_i-2\sum_{i=1}^nx_iy_i+nc^2 =∑i=1nxi2+∑i=1nyi2+2c∑i=1nxi−2c∑i=1nyi−2∑i=1nxiyi+nc2
观察柿子可以发现,出 ∑ i = 1 n x i y i \sum_{i=1}^nx_iy_i ∑i=1nxiyi外,均为定值(关于 c c c的柿子是一个二次函数,存在极值),为了使用 f f t fft fft解决上述问题,将柿子进行化简, ∑ i = 1 n x i y i = ∑ i = 1 n x n − i + 1 y i \sum_{i=1}^nx_iy_i=\sum_{i=1}^{n}x_{n-i+1}y_i ∑i=1nxiyi=∑i=1nxn−i+1yi,上述可以用 f f t fft fft快速求解。
由于全局最小值,相当于求上述 ∑ i = 1 n x n − i + 1 y i \sum_{i=1}^{n}x_{n-i+1}y_i ∑i=1nxn−i+1yi最大值, x i , y i x_i,y_i xi,yi相当于多项式 A , B A,B A,B第 i i i项的系数, ∑ i = 1 n x n − i + 1 y i \sum_{i=1}^{n}x_{n-i+1}y_i ∑i=1nxn−i+1yi就是 n + 1 n+1 n+1项的系数。
旋转可以看做平移,将 A A A平移为两倍,答案就是 m i n [ n + 1 ∼ 2 n ] min[n+1\sim 2n] min[n+1∼2n]项的系数
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+10, M = N * 2, inf = 1e8;
const double PI = acos(-1);
int n, m;
int rev[N], bit, tot;
struct Complex{
double x, y;
Complex operator+ (const Complex& t) const { return {x + t.x, y + t.y}; }
Complex operator- (const Complex& t) const{ return {x - t.x, y - t.y}; }
Complex operator* (const Complex& t) const{ return {x * t.x - y * t.y, x * t.y + y * t.x}; }
}a[N], b[N];
void fft(Complex a[], int inv){
for(int i = 0; i < tot; i++)
if(i < rev[i]) swap(a[i], a[rev[i]]);
for(int mid = 1; mid < tot; mid <<= 1){
Complex w1 = Complex({cos(PI/mid), inv * sin(PI/mid)});
for(int i = 0; i < tot; i += mid * 2){
Complex wk = Complex({1, 0});
for(int j = 0; j < mid; j ++, wk = wk * w1){
Complex x = a[i + j], y = wk * a[i + j + mid];
a[i + j] = x + y, a[i + j + mid] = x - y;
}
}
}
}
double A[N], B[N];
ll a2, b2, suma, sumb;
int main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin>>n>>m;
while((1 << bit) < 3 * n + 1) bit++;
tot = 1 << bit;
for(int i = 0; i < tot; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));
for(int i = 1; i <= n; i++) cin>>A[i], suma += A[i], a2 += A[i] * A[i];
for(int i = 1; i <= n; i++) cin>>B[i], sumb += B[i], b2 += B[i] * B[i];
for(int i = 1; i <= n; i++) a[i] = a[i+n] = {A[i], 0}, b[i] = {B[i], };
reverse(b + 1, b + n + 1);
fft(a, 1), fft(b, 1);
for(int i = 0; i <= tot; i++) a[i] = a[i] * b[i];
fft(a, -1);
for(int i = 0; i <= tot; i++) a[i].x = (int)(a[i].x/tot+0.5);
int ans = 1e9;
for(int i = 1; i <= n; i++){
for(int x = -m; x <= m; x++){
int tmp = a2 + b2 + n * x * x;
tmp += 2 * x * (suma - sumb);
ans = min(ans, tmp - 2 * (int) a[i+n].x);
}
}
cout<<ans<<endl;
return 0;
}