题目链接 【AHOI2017/HNOI2017】礼物
<!--more-->
题解
其实修改亮度可以看做对其中一串手环整体加或者整体减去,所以只要在括号里加上
就可以了。原来的式子就变长了这样:
我们继续拆一下式子
然后你会惊奇地发现,枚举了之后,除了最后一项之外都是常量。同时又是以最小化这个式子的值为目标的,所以只需要最大化
就可以了。
现在把翻转,那么原来的式子就变成了这样
那你再把下标往左整体平移一下,
这不是卷积吗?那我们只需要做一遍再错位处理一下,取一个最大值就可以了。
思考下的本质,画一张图,就能理解如何错位了。
代码
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
const int MAXN = 1e6 + 7;
const double PI = std::acos(-1.0);
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], b[MAXN];
int sum1, sum2;
int len = 1, e = 0;
int r[MAXN], v[MAXN];
void fft(Complex *p, int type) {
for (int i = 0; i < len; i++) {
if (i < r[i]) std::swap(p[i], p[r[i]]);
}
for (int l = 1; l < len; l <<= 1) {
Complex root(std::cos(PI / l), type * std::sin(PI / l));
for (int i = 0; i < len; i += (l << 1)) {
Complex t(1.0, 0.0);
for (int j = 0; j < l; j++, t = t * root) {
Complex x = p[i + j], y = t * p[i + l + j];
p[i + j] = x + y;
p[i + l + j] = x - y;
}
}
}
}
int main(int argc, char *argv[]) {
int n, m;
scanf("%d %d", &n, &m); n--;
for (int i = 0; i <= n; i++) {
scanf("%lf", &a[i].x);
}
for (int i = 0; i <= n; i++) {
scanf("%lf", &b[i].x);
}
for (int i = 0; i <= n; i++) {
sum1 += a[i].x * a[i].x + b[i].x * b[i].x;
sum2 += a[i].x - b[i].x;
}
int n2 = n + n;
std::reverse(b, b + n + 1);
while (len <= n2) len <<= 1, e++;
for (int i = 0; i < len; i++) {
r[i] = (r[i >> 1] >> 1) | ((i & 1) << (e - 1));
}
fft(a, 1), fft(b, 1);
for (int i = 0; i <= len; i++) {
a[i] = a[i] * b[i];
}
fft(a, -1);
for (int i = 0; i <= n2; i++) {
v[i] = (int)(a[i].x / len + 0.5);
}
int val = v[n];
for (int i = 0; i <= n - 1; i++) {//错位处理
if (val < v[i] + v[i + n + 1]) {
val = v[i] + v[i + n + 1];
}
}
val *= 2;
int ans = 0x7fffffff;
for (int i = -m; i <= m; i++) {
ans = std::min(ans, sum2 * 2 * i + (n + 1) * i * i - val);
}
printf("%d\n", ans + sum1);
return 0;
}

京公网安备 11010502036488号