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\)

那么差异值为:

\[
\begin{aligned}
&=\sum\limits_{i = 1}^{n} (d_i + r)^2 \&=\sum\limits_{i = 1}^{n}(d_i^2 + r^2 + 2d_ir) \&=\sum\limits_{i = 1}^{n} d_i^2 + nr^2 + 2r\sum\limits_{i = 1}^{n} d_i \\end{aligned}
\]

后边可以直接确定,是二次函数最小值点

我们只需最小化

\[\sum\limits_{i = 1}^{n} d_i^2\]

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

我们实际求

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

我们令\(t_i = x_{n - i + 1}\)

那么就是求

\[min\{ \sum\limits_{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\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/Mychael/p/8976897.html

时间: 2024-10-08 23:44:50

luogu3723 [AH2017/HNOI2017]礼物 【NTT】的相关文章

BZOJ4827:[AH2017/HNOI2017]礼物——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=4827 https://www.luogu.org/problemnew/show/P3723 题面见原题. 参考了洛谷一些题解. 先推式子,x数组为a,y数组为b,将b数组倍长后有: 因为c的范围在[-m,m]之间,而m=100,且稍加思考后发现k在1,3,4项中是无用的,所以通过枚举c取得1,3,4项和的最小值. 考虑计算第二项,其实是卷积型,实际上将a数组前移并倒转即可得到: 变成了卷积,F

BZOJ4827: [Hnoi2017]礼物

4827: [Hnoi2017]礼物 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 474  Solved: 334[Submit][Status][Discuss] Description 我的室友最近喜欢上了一个可爱的小女生.马上就要到她的生日了,他决定买一对情侣手 环,一个留给自己,一 个送给她.每个手环上各有 n 个装饰物,并且每个装饰物都有一定的亮度.但是在她生日的前一天,我的室友突 然发现他好像拿错了一个手环,而且已经没时间去更换它了

[bzoj4827][Hnoi2017]礼物_FFT

礼物 bzoj-4827 Hnoi-2017 题目大意:给定两个长度为$n$的手环,第一个手环上的$n$个权值为$x_i$,第二个为$y_i$.现在我可以同时将所有的$x_i$同时加上自然数$c$.我也可以将第一个手环任意旋转.旋转后每一个$x$对应一个$y$,那么代价为$\sum\limits_{i=0}^{n-1} (x_i-y_i)^2$.求最小代价. 注释:$1\le n\le 10^5$,$0\le maxval \le 100$. 想法: 水题啊..... 推推式子,我们假设就加了$

HNOI2017礼物

礼物 这估计是最水,最无脑的一道题了 首先发现总和最接近时答案最小 发现答案就是\((\sum_{i=1}^{n}a[i]^2+b[i]^2)-2*max(\sum_{i=1}^{n}a[i]*b[i+j])(0<=j<=n-1)\) 前面随便算,主要是后面那个式子,其实就是两个数列错位相乘加起来最大值 把\(b\)反过来就变成\(\sum_{i=1}^{n}a[i]*b[n-i-j])(0<=j<=n-1)\),直接就多项式卷积,FFT一算就行了. // luogu-judger

[HNOI2017]礼物

题目描述 我的室友最近喜欢上了一个可爱的小女生.马上就要到她的生日了,他决定买一对情侣手环,一个留给自己,一个送给她.每个手环上各有 n 个装饰物,并且每个装饰物都有一定的亮度. 但是在她生日的前一天,我的室友突然发现他好像拿错了一个手环,而且已经没时间去更换它了!他只能使用一种特殊的方法,将其中一个手环中所有装饰物的亮度增加一个相同的自然数 c(即非负整数).并且由于这个手环是一个圆,可以以任意的角度旋转它,但是由于上面装饰物的方向是固定的,所以手环不能翻转.需要在经过亮度改造和旋转之后,使得

bzoj 4827: [HNOI2017]礼物 (FFT)

一道FFT 然而据说暴力可以水70分 然而我省选的时候看到了直接吓傻了  连暴力都没打 太弱了啊QAQ emmmm 详细的拆开就看其他题解吧233 最后那一步卷积其实我一直没明白 后来画画图终于懂了 只要把其中一个反过来 多项式乘法的结果中的每一项系数就对应某一个Σx[i] * y[j] 的结果 前面几项是不完全的结果 但是太小了就被忽略啦 代码如下 /************************************************************** Problem:

[BZOJ 4827][Hnoi2017]礼物(FFT)

Description 我的室友最近喜欢上了一个可爱的小女生.马上就要到她的生日了,他决定买一对情侣手 环,一个留给自己,一 个送给她.每个手环上各有 n 个装饰物,并且每个装饰物都有一定的亮度.但是在她生日的前一天,我的室友突 然发现他好像拿错了一个手环,而且已经没时间去更换它了!他只能使用一种特殊的方法,将其中一个手环中所有 装饰物的亮度增加一个相同的自然数 c(即非负整数).并且由于这个手环是一个圆,可以以任意的角度旋转它, 但是由于上面 装饰物的方向是固定的,所以手环不能翻转.需要在经过

[AH/HNOI2017]礼物

题目描述 我的室友最近喜欢上了一个可爱的小女生.马上就要到她的生日了,他决定买一对情侣手环,一个留给自己,一个送给她.每个手环上各有 n 个装饰物,并且每个装饰物都有一定的亮度. 但是在她生日的前一天,我的室友突然发现他好像拿错了一个手环,而且已经没时间去更换它了!他只能使用一种特殊的方法,将其中一个手环中所有装饰物的亮度增加一个相同的自然数 c(即非负整数).并且由于这个手环是一个圆,可以以任意的角度旋转它,但是由于上面装饰物的方向是固定的,所以手环不能翻转.需要在经过亮度改造和旋转之后,使得

BZOJ 4827 [Hnoi2017]礼物 ——FFT

题目上要求一个循环卷积的最小值,直接破环成链然后FFT就可以了. 然后考虑计算的式子,可以分成两个部分分开计算. 前半部分FFT,后半部分扫一遍. #include <map> #include <ctime> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <alg