bzoj 4827 [Hnoi2017]礼物(FFT)

来源:互联网 发布:c 高级编程 第7版 pdf 编辑:程序博客网 时间:2024/06/05 20:23

题意:有两个长度为n的序列,序列元素为[1,m]。定义两个序列的差异值为∑ni=1(x[i]−y[i])2现在可以给第一个序列加上一个长度c,第二个序列可以任意旋转,问最小差异值。n≤50000,m≤100

思路:
ni=1(xiyj+c)2
=ni=1(xiyj)2+2cni=1(xiyj)+ni=1c2
=ni=1x2i+ni=1y2i2ni=1xiyj+2cni=1xi2cni=1yi+ni=1c2
显然c是可以确定的。因为后三项其实是一个关于c的二次方程,易得c的最小值,然后可以发现我们要求的就是ni=1(xiyj)的最大值。FFT即可。

#include <bits/stdc++.h>using namespace std;const int maxn = 1 << 17;const double pi = acos(-1.0);struct data{    double x, y;    data()    {        x = y = 0;    }    data(double x0, double y0)    {        x = x0, y = y0;    }    data operator+(const data &a)const    {        return data(x + a.x, y + a.y);    }    data operator-(const data &a)const    {        return data(x - a.x, y - a.y);    }    data operator*(const data &a)const    {        return data(x * a.x - y * a.y, x * a.y + y * a.x);    }};void fft(data *a, int n, int flag){    int i, j, k;    for(int i = 0, k = 0 ; i < n ; i ++ )    {        if(i > k) swap(a[i], a[k]);        for(j = (n >> 1) ; (k ^= j) < j ; j >>= 1);    }    for(int k = 2 ; k <= n ; k <<= 1)    {        data wn(cos(2 * pi * flag / k), sin(2 * pi * flag / k));        for(i = 0 ; i < n ; i += k)        {            data t, w(1, 0);            for(j = i ; j < i + (k >> 1) ; j ++, w = w * wn)                t = w * a[j + (k >> 1)], a[j + (k >> 1)] = a[j] - t, a[j] = a[j] + t;        }    }}data a[maxn], b[maxn];double x[maxn], y[maxn];int main(){    int n, m;    scanf("%d%d", &n, &m);    double sumx = 0, sumy = 0, sumx2 = 0, sumy2 = 0, c = 0;    for(int i = 0; i < n; i++)  scanf("%lf", &x[i]), sumx += x[i], sumx2 += x[i] * x[i];    for(int i = 0; i < n; i++)  scanf("%lf", &y[i]), sumy += y[i], sumy2 += y[i] * y[i];    c = floor((sumy - sumx) / n + 0.5);    double ans = 0;    ans = ans + sumx2 + sumy2 + 2.0 * c * (sumx - sumy) + 1.0 * n * c * c;    for(int i = 0; i < 2 * n; i++)  a[i].x = x[i % n];    for(int i = 0; i < n; i++)  b[i].x = y[n-i-1];    int len = 1;    while(len < 2 * n)  len <<= 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);    double maxx = 0;    for(int i = n - 1; i < 2*n-1; i++)  maxx = max(maxx, round(a[i].x / len));    ans = ans - 2.0 * maxx;    printf("%.0f\n", ans);    return 0;}
原创粉丝点击