• luogu3723 [AH2017/HNOI2017]礼物 【NTT】


    题目

    我的室友最近喜欢上了一个可爱的小女生。马上就要到她的生日了,他决定买一对情侣手 环,一个留给自己,一
    个送给她。每个手环上各有 n 个装饰物,并且每个装饰物都有一定的亮度。但是在她生日的前一天,我的室友突
    然发现他好像拿错了一个手环,而且已经没时间去更换它了!他只能使用一种特殊的方法,将其中一个手环中所有
    装饰物的亮度增加一个相同的自然数 c(即非负整数)。并且由于这个手环是一个圆,可以以任意的角度旋转它,
    但是由于上面 装饰物的方向是固定的,所以手环不能翻转。需要在经过亮度改造和旋转之后,使得两个手环的差
    异值最小。在将两个手环旋转且装饰物对齐了之后,从对齐的某个位置开始逆时针方向对装饰物编号 1,2,…,n,
    其中 n 为每个手环的装饰物个数,第 1 个手环的 i 号位置装饰物亮度为 xi,第 2 个手 环的 i 号位置装饰物
    亮度为 yi,两个手环之间的差异值为(参见输入输出样例和样例解释): sum_{i=1}^{n}(x_i-y_i)^2麻烦你帮他
    计算一下,进行调整(亮度改造和旋转),使得两个手环之间的差异值最小, 这个最小值是多少呢?

    输入格式

    输入数据的第一行有两个数n, m,代表每条手环的装饰物的数量为n,每个装饰物的初始 亮度小于等于m。
    接下来两行,每行各有n个数,分别代表第一条手环和第二条手环上从某个位置开始逆时 针方向上各装饰物的亮度。
    1≤n≤50000, 1≤m≤100, 1≤ai≤m

    输出格式

    输出一个数,表示两个手环能产生的最小差异值。
    注意在将手环改造之后,装饰物的亮度 可以大于 m。

    输入样例

    5 6

    1 2 3 4 5

    6 3 3 4 5

    输出样例

    1

    提示

    【样例解释】

    需要将第一个手环的亮度增加1,第一个手环的亮度变为: 2 3 4 5 6 旋转一下第二个手环。对于该样例,是将第

    二个手环的亮度6 3 3 4 5向左循环移动 2017-04-15 第 6 页,共 6 页 一个位置,使得第二手环的最终的亮度为

    :3 3 4 5 6。 此时两个手环的亮度差异值为1。

    题解

    我们设(d_i = x_i + y_i)
    那么差异值为:

    [egin{aligned} &=sumlimits_{i = 1}^{n} (d_i + r)^2 \ &=sumlimits_{i = 1}^{n}(d_i^2 + r^2 + 2d_ir) \ &=sumlimits_{i = 1}^{n} d_i^2 + nr^2 + 2rsumlimits_{i = 1}^{n} d_i \ end{aligned} ]

    后边可以直接确定,是二次函数最小值点
    我们只需最小化

    [sumlimits_{i = 1}^{n} d_i^2 =sumlimits_{i = 1}^{n} (x_i^2 + y_i^2 - 2x_iy_i) ]

    即最大化

    [sumlimits_{i = 1}^{n} x_iy_i ]

    如果我们将(y)倍长,对于一种错位关系,(x_i与y_i)的差为定值
    我们实际求

    [min{ sumlimits_{j - i = k} x_i * y_j} qquad k in [0,n - 1] ]

    我们令(t_i = x_{n - i + 1})
    那么就是求

    [min{ sumlimits_{j + i= n + 1 + k} t_i * y_j} qquad k in [0,n - 1] ]

    说白了就是将(x)翻转

    然后NTT即可

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    using namespace std;
    const int maxn = 400005,maxm = 100005,INF = 1000000000;
    inline int read(){
        int out = 0,flag = 1; char c = getchar();
        while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
        while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
        return out * flag;
    }
    const int G = 3,P = 998244353;
    LL A[maxn],B[maxn],L,R[maxn],n,m;
    LL qpow(LL a,LL b){
        LL ans = 1;
        for (; b; b >>= 1,a = a * a % P)
            if (b & 1) ans = ans * a % P;
        return ans;
    }
    void NTT(LL* a,int f){
        for (int i = 0; i < n; i++) if (i < R[i]) swap(a[i],a[R[i]]);
        for (int i = 1; i < n; i <<= 1){
            LL gn = qpow(G,(P - 1) / (i << 1));
            for (int j = 0; j < n; j += (i << 1)){
                LL g = 1,x,y;
                for (int k = 0; k < i; k++,g = g * gn % P){
                    x = a[j + k]; y = g * a[j + k + i] % P;
                    a[j + k] = (x + y) % P; a[j + k + i] = (x - y + P) % P;
                }
            }
        }
        if (f == 1) return;
        int nv = qpow(n,P - 2); reverse(a + 1,a + n);
        for (int i = 0; i < n; i++) a[i] = 1ll * a[i] * nv % P;
    }
    LL N,a[maxn],b[maxn],sum;
    LL ans = 0;
    int main(){
        N = read(); read();
        REP(i,N) sum += (a[i] = read());
        REP(i,N) sum -= (b[i] = read());
        LL r = -sum / N;
    	ans = INF;
    	ans = min(ans,N * (r - 1) * (r - 1) + 2 * sum * (r - 1));
    	ans = min(ans,N * r * r + 2 * sum * r);
    	ans = min(ans,N * (r + 1) * (r + 1) + 2 * sum * (r + 1));
        REP(i,N) ans += a[i] * a[i] + b[i] * b[i];
        REP(i,N) A[i] = a[N - i + 1],B[i] = B[N + i] = b[i];
        m = 3 * N; L = 0;
        for (n = 1; n <= m; n <<= 1) L++;
        for (int i = 0; i < n; i++) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
        NTT(A,1); NTT(B,1);
        for (int i = 0; i < n; i++) A[i] = A[i] * B[i] % P;
        NTT(A,-1);
        LL tmp = 0;
        for (int i = N + 1; i <= N + N; i++) tmp = max(tmp,A[i]);
        ans -= 2 * tmp;
        printf("%lld
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    20160813上午训练记录
    [bzoj 2159]Crash的文明世界
    【娱乐】高端小游戏Manufactoria
    【教程】如何正确的写一个Lemon/Cena的SPJ(special judge)
    [CF]codeforces round#366(div2)滚粗记
    洛谷 [P3265] 装备购买
    POJ 1830 开关问题
    洛谷 [P4035] 球形空间生成器
    BZOJ 2973 入门OJ4798 石头游戏
    洛谷 [P1939] 矩阵加速数列
  • 原文地址:https://www.cnblogs.com/Mychael/p/8976897.html
Copyright © 2020-2023  润新知