zoukankan      html  css  js  c++  java
  • 4827: [Hnoi2017]礼物

    4827: [Hnoi2017]礼物

    链接

    分析:

      求最小的$sum_{i=1}^{n}(x_i-y_i)^2$

      设旋转了j位,每一位加上了c。

      $sumlimits_{i=1}^{n}(x_{i+j}+c-y_i)^2$

      $=sumlimits_{i=1}^{n}x_{i+j}^2+y_i^2+c^2+2x_{i+j}c-2y_ic-2x_{i+j}y_i$

      $=sum x_i^2+sum y_i^2+nc^2+2c sum (x_i-y_i)-2sum x_{i+j}y_i$

      发现只有最后一项是要求的。

      $sum x_{i+j}y_i$ 然后把y翻转一下,就是$sum x_{i+j}y_{n - i +1}$,再把x加倍即可。

      考虑为什么这样就解决了,如果不旋转,那么$a[1],a[2],a[3]$与$b[1],b[2],b[3]$相乘,那么得到的$c[4]=a[1] imes b[3]+a[2] imes b[2]+a[3] imes b[1]$,所以如果翻转b,c[4]就是旋转0位的答案。在a后面加倍一次,得到那么f[5]就是旋转1位的答案,同理f[6]是旋转2位的答案。

      而且c是可以直接求出的,可以不用枚举,戳这

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<cctype>
    #include<set>
    #include<queue>
    #include<vector>
    #include<map>
    using namespace std;
    typedef long long LL;
    
    inline int read() {
        int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    }
    
    const int N = 200005, INF = 1e9;
    const double Pi = acos(-1.0), eps = 1e-10;
    int rev[N], f[N], x[N], y[N];
    struct Com{ 
        double x, y; 
        Com(double _x = 0.0,double _y = 0) { x = _x, y = _y; }
    }a[N], b[N];
    Com operator + (const Com &A,const Com &B) { return Com(A.x + B.x, A.y + B.y); }
    Com operator - (const Com &A,const Com &B) { return Com(A.x - B.x, A.y - B.y); }
    Com operator * (const Com &A,const Com &B) { return Com(A.x * B.x - A.y * B.y, A.x * B.y + A.y * B.x); }
    
    void FFT(Com *a,int n,int ty) {
        for (int i = 0; i < n; ++i) if (i < rev[i]) swap(a[i], a[rev[i]]);
        Com w1, w, t, u;
        for (int m = 2; m <= n; m <<= 1) {
            w1 = Com(cos(2 * Pi / m), ty * sin(2 * Pi / m));
            for (int i = 0; i < n; i += m) {
                w = Com(1, 0);
                for (int k = 0; k < (m >> 1); ++k) {
                    t = w * a[i + k + (m >> 1)];
                    u = a[i + k];
                    a[i + k] = u + t;
                    a[i + k + (m >> 1)] = u - t;
                    w = w * w1;
                }
            }
        }
    }
    void mul(Com *a,Com *b,int len) {
        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);
        for (int i = 0; i <= len; ++i) f[i] = (int)(a[i].x / (double)len + 0.5);
    }
    int main() {
        int n = read(), m = read(), len = 1, lg = 0, Sx = 0, Sy = 0, S = 0;
        while (len <= n + n) len <<= 1, lg ++;
        for (int i = 1; i <= len; ++i) 
            rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
        for (int i = 0; i < n; ++i) 
            x[i] = read(), Sx += (x[i] * x[i]), S += 2 * x[i];    
        for (int i = 0; i < n; ++i) 
            y[i] = read(), Sy += (y[i] * y[i]), S -= 2 * y[i];
        for (int i = 0; i < n + n; ++i) a[i] = Com(x[i % n], 0);
        for (int i = 0; i < n; ++i) b[i] = Com(y[n - i - 1], 0);
        mul(a, b, len);
        int ans = INF;
        for (int c = -m; c <= m; ++c) 
            for (int i = n; i < n + n; ++i) 
                ans = min(ans, Sx + Sy + c * S + n * c * c - 2 * f[i]);
        cout << ans;
        return 0;
    }
  • 相关阅读:
    Jmeter聚合报告、
    Jmeter中控件基本概念+工具使用系列(接口自动化、性能测试)
    PhpStorm创建Drupal模块项目开发教程(3)
    PhpStorm创建Drupal模块项目开发教程(2)
    PhpStorm创建Drupal模块项目开发教程
    IntelliJ IDEA 发布13版本——创造java奇迹
    图文解说PhpStorm 7.0版本新增内置工具
    图文解说PhpStorm 7.0版本语法着色
    图文解说PhpStorm 7.0版本支持PHP 5.5
    ReSharper 8.1支持TypeScript语言之代码检查特征
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10434173.html
Copyright © 2011-2022 走看看