题目链接 【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; }