bzoj4827 Hnoi2017 礼物

题目链接

solution

将式子展开

\[\sum\limits_{i=1}^n(x_i - y_i + c)^2 \]
\[=\sum\limits_{i=1}^nx_i^2+y_i^2-2x_iy_i+2c(x_i-y_i)+c^2\]
\[=\sum\limits_{i=1}^nx_i^2+\sum\limits_{i=1}^ny_i^2-2\sum\limits_{i=1}^nx_iy_i+2c(\sum\limits_{i=1}^nx_i-\sum\limits_{i=1}^ny_i)+nc^2\]

前面\(\sum\limits_{i=1}^nx_i^2+\sum\limits_{i=1}^ny_i^2\)是定值。
后面\(2c(\sum\limits_{i=1}^nx_i-\sum\limits_{i=1}^ny_i)+nc^2\)是个二次函数。最值很好求。
所以问题就是要最大化\(\sum\limits_{i=1}^nx_iy_i\),

我们设将\(y\)这个手环左移了\(k\)下。那么答案就变为\(\sum\limits_{i=1}^nx_iy_{i+k}\)

将x序列倒过来就变成了卷积的形式\(\sum\limits_{i=1}^nx_{n-i}y_{i+k}\)

code

/*
* @Author: wxyww
* @Date:   2019-07-21 20:49:19
* @Last Modified time: 2019-07-21 21:33:06
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
#include<cmath>
using namespace std;
typedef long long ll;
const int N = 1000000 + 100;
ll read() {
    ll x=0,f=1;char c=getchar();
    while(c<'0'||c>'9') {
        if(c=='-') f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}
int Re[N],n,m,limit = 1;
struct complex {
    double x,y;
    complex(double xx = 0,double yy = 0) {x = xx;y = yy;}
}a[N],b[N];
complex operator + (const complex &A,const complex &B) {
    return complex(A.x + B.x,A.y + B.y);
}
complex operator - (const complex &A,const complex &B) {
    return complex(A.x - B.x,A.y - B.y);
}
complex operator * (const complex &A,const complex &B) {
    return complex(A.x * B.x - A.y * B.y,A.x * B.y + A.y * B.x);
}
double ans;
double T;
const double pi = acos(-1.0);
void FFT(complex *A,int type) {
    for(int i = 0;i < limit;++i) if(i < Re[i]) swap(A[i],A[Re[i]]);
    for(int mid = 1;mid < limit;mid <<= 1) {
        complex Wn(cos(pi / mid),type * sin(pi / mid));
        for(int R = mid << 1,j = 0;j < limit;j += R) {
            complex w(1.0,0);
            for(int k = 0;k < mid;++k,w = w * Wn) {
                complex x = A[j + k],y = w * A[j + mid + k];
                A[j + mid + k] = x - y;
                A[j + k] = x + y;
            }
        }
    }
}
ll calc(ll x) {
    return n * x * x + 2 * T * x;
}
int main() {
    n = read(),m = read();
    for(int i = 0;i < n;++i) {
        int x = read();
        a[n - i].x = x;
        ans += x * x;
        T += x;
    }

    for(int i = 0;i < n;++i) {
        int y = read();
        b[i].x = b[i + n].x = y;
        ans += y * y;
        T -= y;
    }

    int num = 0;
    while(limit <= n * 3) limit <<= 1,num++;
    for(int i = 0;i <= limit;++i) Re[i] = Re[i >> 1] >> 1 | ((i & 1) << (num - 1));

    FFT(a,1);
    FFT(b,1);
    for(int i = 0;i <= limit;++i) a[i] = a[i] * b[i];
    FFT(a,-1);

    double ret = 0;
    for(int i = 0;i <= limit;++i) ret = max(ret,round(a[i].x / limit));

    ans -= 2 * ret;
    
    ans += calc(round(-T / n));

    printf("%.0lf",ans);

    return 0;
}
posted @ 2019-07-21 21:56 wxyww 阅读(...) 评论(...) 编辑 收藏