zoukankan      html  css  js  c++  java
  • P3723 [AH2017/HNOI2017]礼物 [FFT]

    P3723 [AH2017/HNOI2017]礼物

    题目描述

    给出两个数列x,yx, y, 长度都为NN;
    定义差异值为

    i=1N(xiyi)2sum_{i=1}^N(x_i-y_i)^2

    可以将任意数列加上任意自然数dd, 求最小差异值


    数据范围

    30%的数据满足n500,m10n≤500, m≤10
    70%的数据满足n5000n≤5000
    100%的数据满足1n50000,1m100,1aim1≤n≤50000, 1≤m≤100, 1≤ai≤m


    Solution

    假设将其中一个加上 bb
    b[m,m]b ∈ [-m, m]
    则差异值为
    i=1N(xi+byi)2sum_{i=1}^N (x_i+b-y_i)^2
    拆开得到
    i=1N(xi2+b2+yi2+2bxi2xiyi2byi)sum_{i=1}^N (x_i^2+b^2+y_i^2+2bx_i-2x_iy_i-2by_i)
    化简
    i=1Nxi2+i=1Nyi2+2bi=1N(xiyi)+Nb22i=1Nxiyisum_{i=1}^N x_i^2 + sum_{i=1}^N y_i^2 + 2bsum_{i=1}^N (x_i-y_i) + Nb^2 -2sum_{i=1}^N x_iy_i
    由于可以改变项链装饰物顺序, 所以 i=1Nxiyisum_{i=1}^N x_iy_i 不确定值
    于是可以考虑枚举xx数列的所有旋转能够得到的顺序, bb的值, 再去计算答案
    复杂度 O(N2M)O(N^2M)

    70 3030 pts get .
    继续思考怎么优化

    思考 .
    思考.
    思考.
    思考.
    思考.
    思考.

    发现最后一项是可以O(N2)O(N^2)预处理的,
    于是 7070 pts get.
    继续思考怎么优化

    思考.
    思考.
    思考.
    思考.
    思考.
    思考.

    发现最后一项 : i=1Nxiyisum_{i=1}^N x_iy_i

    反转yy数列,
    可以变成卷积的形式 : i=1Nxiyni+1sum_{i=1}^N x_iy_{n-i+1}

    即可用 FFTFFT 求出多项式 AA :

    Ai=j=1ixjynj+1A_i = sum_{j=1}^i x_jy_{n-j+1}
    又想到序列环是可以旋转的, 于是 宣布这道题无解
    因为已经拆开了环, 即将yy数列的长度延长为原来的2倍
    若没有延长, 多项式最高次幂为An+1A_{n+1} , 是由xiyni+1x_iy_{n-i+1}, i[1,N]i ∈ [1, N] 得到的
    可以想到An+2A_{n+2}是有由xiyni+2x_iy_{n-i+2} , i[1,N]i ∈ [1, N] 得到的
    进而 An+kA_{n+k}是有由 xiyni+1+kx_iy_{n-i+1+k} , i[1,N]i ∈ [1, N] 得到的
    于是得出结论, An+kA_{n+k}表示旋转kk次后的i=1Nxiyni+1sum_{i=1}^N x_iy_{n-i+1}
    AC思路 :将y数组反转, 并且x延长1倍, 计算卷积, 最后直接计算取最优值即可


    Addition

    注意精度问题, double转long long需要 -exp


    Code

    #include<bits/stdc++.h>
    #define reg register
    
    const double Pi = acos(-1);
    const int maxn = 1e6 + 10;
    
    typedef long long ll;
    int N, M, Len;
    int rev[maxn];
    
    struct Complex{
            double x, y;
            Complex(double x=0, double y=0):x(x), y(y) {}
    } A[maxn], B[maxn];
    
    Complex operator + (Complex a, Complex b){ return Complex(a.x+b.x, a.y+b.y); }
    Complex operator - (Complex a, Complex b){ return Complex(a.x-b.x, a.y-b.y); }
    Complex operator * (Complex a, Complex b){ return Complex(a.x*b.x-a.y*b.y, b.x*a.y+a.x*b.y); }
    
    void FFT(Complex *F, int opt){
            for(reg int i = 0; i < Len; i ++)
                    if(i < rev[i]) std::swap(F[i], F[rev[i]]);
            for(reg int p = 2; p <= Len; p <<= 1){
                    int l = p >> 1;
                    Complex delt(cos(Pi/l), opt*sin(Pi/l));
                    for(reg int i = 0; i < Len; i += p){
                            Complex w(1.0, 0.0);
                            for(reg int k = i; k < i + l; k ++){
                                    Complex Temp = F[k+l] * w;
                                    F[k+l] = F[k] - Temp;
                                    F[k] = F[k] + Temp;
                                    w = w * delt;
                            }
                    }
            }
    }
    
    int main(){
            scanf("%d%d", &N, &M);
            for(reg int i = 1; i <= N; i ++) scanf("%lf", &A[i].x), A[i+N] = A[i];
            for(reg int i = 1; i <= N; i ++) scanf("%lf", &B[i].x);
            ll base = 0, base2 = 0;
            for(reg int i = 1; i <= N; i ++) base += 1ll*A[i].x*A[i].x + 1ll*B[i].x*B[i].x;
            for(reg int i = 1; i <= N; i ++) base2 += A[i].x-B[i].x;
            for(reg int i = 1; i <= N>>1; i ++) std::swap(B[i], B[N-i+1]);
            int bit_num = 0; Len = 1;
            while(Len <= (N<<2)) Len <<= 1, bit_num ++;
            for(reg int i = 0; i <= Len; i ++) rev[i] = (rev[i>>1]>>1) | ((i&1) << bit_num-1);
            FFT(A, 1), FFT(B, 1);
            for(reg int i = 0; i <= Len; i ++) A[i] = A[i] * B[i];
            FFT(A, -1);
            for(reg int i = 0; i <= Len; i ++) A[i].x /= Len*1.0;
            ll Ans = 999999999999999999;
            for(reg int i = N+1; i <= N<<1; i ++)
                    for(reg int b = -M; b <= M; b ++){
                            ll Temp = base + base2*2*b + 1ll*N*b*b - 2ll*(A[i].x-0.02);
                            Ans = std::min(Ans, Temp);
                    }
            printf("%lld
    ", Ans);
            return 0;
    }
    
  • 相关阅读:
    Kafka速览
    分布式消息中间件(二)ActiveMQ
    PageUtil 分页
    Tomcat配置
    CryptographyUtil盐加密
    InitComponent的使用
    Shiro权限总结
    【转】Java自学之路——by马士兵
    ExcelUtil
    Java操作Excel之Poi
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822664.html
Copyright © 2011-2022 走看看