题意:洛谷P3723
求按题意操作后 ∑ i = 1 n ( x i − y i ) 2 \sum_{i=1}^n(x_i-y_i)^2 ∑i=1n(xi−yi)2的最小值
分析:
两个同时增加亮度没有意义,肯定只有一个增加亮度,也可以理解为只有一个降低亮度。
假设增加的亮度为
c
c
c,注意
c
c
c可以是正数(增加)也可以是负数(降低)
那么即求
∑
i
=
1
n
(
x
i
−
y
i
+
c
)
2
\sum_{i=1}^n(x_i-y_i+c)^2
∑i=1n(xi−yi+c)2的最小值。
展开这个多项式得到
∑
i
=
1
n
x
i
2
+
y
i
2
+
c
2
+
2
c
x
i
−
2
c
y
i
−
2
x
i
y
i
\sum_{i=1}^{n}x_i^2+y_i^2+c^2+2cx_i-2cy_i-2x_iy_i
∑i=1nxi2+yi2+c2+2cxi−2cyi−2xiyi
↓
↓
↓
∑
i
=
1
n
x
i
2
+
∑
i
=
1
n
y
i
2
+
n
c
2
+
2
c
∑
i
=
1
n
x
i
−
y
i
−
2
∑
i
=
1
n
x
i
y
i
\sum_{i=1}^{n}x_i^2+\sum_{i=1}^{n}y_i^2+nc^2+2c\sum_{i=1}^{n}x_i-y_i-2\sum_{i=1}^{n}x_iy_i
∑i=1nxi2+∑i=1nyi2+nc2+2c∑i=1nxi−yi−2∑i=1nxiyi
可以发现这个式子前
2
2
2项是定值,直接求即可。
而第
3
、
4
3、4
3、4项则是以
c
c
c为未知数的二次函数,由于
n
>
0
n>0
n>0,故二次函数有最小值,当
c
=
c=
c=
−
2
a
b
\frac{-2a}{b}
b−2a时得到最小值。
最后一项求
∑
i
=
1
n
x
i
y
i
\sum_{i=1}^{n}x_iy_i
∑i=1nxiyi的值,我们可以反转
x
x
x数列,做卷积
∑
i
=
1
n
x
n
−
i
+
1
y
i
\sum_{i=1}^{n}x_{n-i+1}y_i
∑i=1nxn−i+1yi
即可,而现在我们要求的是最大值,那我们将反转后的
x
x
x数列扩大一倍再与
y
y
y做卷积即可,最终求出来的
n
+
1
n+1
n+1
→
\rightarrow
→
2
∗
n
2*n
2∗n项的最大值就是我们要的最大值。为什么(其实我也理解了挺久)?这里我给出一个例子:
原
x
i
x_i
xi:
1
,
2
,
3
,
4
1,2,3,4
1,2,3,4
反转倍长后
x
i
x_i
xi:
4
1
,
3
2
,
2
3
,
1
4
,
4
5
,
3
6
,
2
7
,
1
8
4_1,3_2,2_3,1_4,4_5,3_6,2_7,1_8
41,32,23,14,45,36,27,18
原
y
i
y_i
yi:
4
1
,
3
2
,
2
3
,
1
4
4_1,3_2,2_3,1_4
41,32,23,14
比如第
7
7
7项就等于
2
3
∗
1
4
+
1
4
∗
2
3
+
4
5
∗
3
2
+
3
6
∗
4
1
2_3*1_4+1_4*2_3+4_5*3_2+3_6*4_1
23∗14+14∗23+45∗32+36∗41,其他项同理…
完。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> pii;
typedef pair<LL, LL> pll;
const int maxn = 50000 + 5;
const int maxm = 100 + 5;
const int inf = 0x3f3f3f3f;
const LL mod = 1e9 + 7;//19260817
const double pi = acos(-1.0);
int n, m, L, len, rev[maxn << 3];
LL c, ans, res;
struct Complex{
double x, y;
Complex(double _x = 0, double _y = 0) : x(_x), y(_y){}
Complex operator + (const Complex &a)const{
return Complex(x + a.x, y + a.y);
}
Complex operator - (const Complex &a)const{
return Complex(x - a.x, y - a.y);
}
Complex operator * (const Complex &a)const{
return Complex(x * a.x - y * a.y, x * a.y + y * a.x);
}
}a[maxn << 3], b[maxn << 3];
void FFT(Complex a[], int len, int f){
Complex x, y, w, wn;
for(int i = 0; i < len; i++) if(i < rev[i]) swap(a[i], a[rev[i]]);
for(int i = 1; i < len; i <<= 1){
wn = Complex(cos(pi / i), f * sin(pi / i));
for(int j = 0, p = i << 1; j < len; j += p){
w = Complex(1, 0);
for(int k = 0; k < i; k++, w = w * wn){
x = a[j + k], y = w * a[j + k + i];
a[j + k] = x + y, a[j + k + i] = x - y;
}
}
}
if(!~f) for(int i = 0; i <= len; i++) a[i].x /= 1.0 * len;
}
int main(){
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++){
scanf("%lf", &a[n - i + 1].x);
a[2 * n - i + 1] = a[n - i + 1].x;
ans += a[n - i + 1].x * a[n - i + 1].x;
res += a[n - i + 1].x;
}
for(int i = 1; i <= n; i++){
scanf("%lf", &b[i].x);
ans += b[i].x * b[i].x;
res -= b[i].x;
}
c = round(-1.0 * res / n);
ans += n * c * c + 2 * c * res;
for(len = 1; len <= n + n + n; len <<= 1) ++L;
for(int i = 0; i < len; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (L - 1));
FFT(a, len, 1), FFT(b, len, 1);
for(int i = 0; i < len; i++) a[i] = a[i] * b[i];
FFT(a, len, -1);
res = 0;
for(int i = n + 1; i <= n + n; i++) res = max(res, (LL)(a[i].x + 0.5));
ans -= 2 * res;
printf("%lld\n", ans);
return 0;
}
萌新 F F T FFT FFT入门