洛谷P3723 [AH2017/HNOI2017]礼物(FFT)

题意:洛谷P3723

求按题意操作后 ∑ i = 1 n ( x i − y i ) 2 \sum_{i=1}^n(x_i-y_i)^2 i=1n(xiyi)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(xiyi+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+2cxi2cyi2xiyi
↓ ↓
∑ 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+2ci=1nxiyi2i=1nxiyi
可以发现这个式子前 2 2 2项是定值,直接求即可。
而第 3 、 4 3、4 34项则是以 c c c为未知数的二次函数,由于 n > 0 n>0 n>0,故二次函数有最小值,当 c = c= c= − 2 a b \frac{-2a}{b} b2a时得到最小值。
最后一项求 ∑ 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=1nxni+1yi
即可,而现在我们要求的是最大值,那我们将反转后的 x x x数列扩大一倍再与 y y y做卷积即可,最终求出来的 n + 1 n+1 n+1 → \rightarrow 2 ∗ n 2*n 2n项的最大值就是我们要的最大值。为什么(其实我也理解了挺久)?这里我给出一个例子:
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 2314+1423+4532+3641,其他项同理…
完。

#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入门

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值