首页 > 其他分享 >【NOIP2021】方差 题解

【NOIP2021】方差 题解

时间:2024-10-22 20:43:03浏览次数:1  
标签:geq limits 方差 dfrac sum 差分 题解 NOIP2021

前言

题目链接:洛谷LOJUOJ

题意简述

给你单调不降序列 \(\{a_n\}\),你可以让 \(a_i \gets a_{i - 1} + a_{i + 1} - a_i\),求操作后方差的最小值。

\(n \leq 10^4\),\(1 \leq a_i \leq 600\)。

题目分析

仔细观察操作,发现实际上是将 \(a_i\) 按照 \(a_{i - 1}\) 和 \(a_{i + 1}\) 的中点 \(\dfrac{a_{i - 1} + a_{i + 1}}{2}\) 对称过去。

发现本质上是交换了 \(i - 1 \sim i\) 和 \(i \sim i + 1\) 的空隙,形式化地说,就是将 \(\{a_n\}\) 的差分数组 \(b_i = a_{i + 1} - a_i\) 交换了 \(b_i\) 和 \(b_{i - 1}\)。邻项交换,想到了什么?会不会和冒泡排序有关呢?我们发现,题目中并没有限制操作次数。再根据排序的性质,我们发现实际上我们可以将差分数组 \(\{b_n\}\) 任意重新排序!

一点说明:

差分数组是 \(n - 1\) 项,我们并不需要考虑 \(a_1 - a_0\)。因为我们只关心 \(a_i\) 的相对关系,而 \(a_1\) 决定 \(\{a_n\}\) 的绝对高度,你可以将 \(a_i \gets a_i - a_1\) 而不影响方差。

怎么重排差分数组来使方差尽量小呢?方差反映 \(\{a_n\}\) 的离散程度,我们需要让 \(a_i\) 尽量集中。经过打表找规律,我们发现,差分数组一定是一个单谷。yy 一下很显然,当然可以证明。

点击展开证明

首先方差 \(\operatorname{Var} \{a_n\} = \dfrac{1}{n} \sum \limits _ {i = 1} ^ n a_i^2 - \overline{a} ^ 2\)。

考虑 \(a_i \gets a_i + d\) 对 \(\operatorname{Var}\) 的影响为 \(\dfrac{1}{n}(d^2 + 2da_i) - \dfrac{1}{n^2}(d^2 + 2d\sum\limits_{j=1}^na_j)\)。

如果希望方差减少,那么 \(\dfrac{1}{n^2}(d^2 + 2d\sum\limits_{j=1}^na_j) \geq \dfrac{1}{n}(d^2 + 2da_i)\),也就是 \(d^2 + 2d\sum\limits_{j=1}^na_j \geq d^2n + 2dna_i\)。

我们交换差分数组 \(d_{i-1}, d_i\),会使 \(a_i \gets a_i + d_i - d_{i - 1}\),此时 \(d = d_i - d_{i - 1}\)。我们讨论 \(d\) 的正负。

  1. \(d \gt 0\),即 \(d_i > d_{i - 1}\):
    把上面不等式两边同时乘以 \(\dfrac{1}{nd}\),得到需要 \(\dfrac{d}{n} + 2\overline{a} \geq d + 2a_i\) 才会使方差减少,移项一下是 \(\overline{a} - a_i \geq \dfrac{d}{2}(1 - \dfrac{1}{n}) \geq 0\),所以要满足 \(a_i \leq \overline{a}\)。由于 \(a\) 不降,满足条件的是 \(a\) 的左侧一部分。操作到最终状态,不存在 \(d_i > d_{i - 1}\),也就是 \(d_i \leq d_{i - 1}\),此时方差最小。
  2. \(d \lt 0\),即 \(d_i < d_{i - 1}\):
    同理得到如果 \(a_i \geq \overline{a}\),最终 \(d_i \geq d_{i - 1}\)。

综合两种情况,差分数组 \(d\) 最终呈单谷时,方差最小。

知道 \(d\) 为单谷之后,要怎么求出最优的那个单谷呢?考虑 DP,从中间最小的开始,往两边扩展。也就是从小到大考虑 \(d_i\),将其插在当前单谷左侧还是右侧。

状态肯定有 \(i\) 一维表示考虑前 \(i\) 个 \(d_i\),记录的结果应该和方差有关。但是似乎不好转移,再加一维 \(j = \sum \limits _ {i = 1} ^ n a_i\),那我们记录的 DP 值只用考虑 \(\sum \limits _ {i = 1} ^ n a_i ^ 2\)。也就是 \(f(i, j)\)。答案就是 \(\min \Big\{n \cdot f(n - 1, j) - j^2\Big\}\),初始 \(f(0, 0) = 0\)。

转移分类讨论。

  1. 加在单谷左侧:

    \[f(i + 1, j + i \cdot d_i) \gets f(i, j) + 2j\cdot d_i + i \cdot d_i^2 \]

  2. 加在单谷右侧:
    我们需要知道 \(\sum \limits _ {j = 1} ^ {i - 1} d_j\) 的值,不妨记作 \(s\)。

    \[f(i + 1, j + s) \gets f(i, j) + s^2 \]

滚一滚空间是 \(\Theta(nV)\),但是时间 \(\Theta(nV^2)\) 不够。发现最后一个测试点 \(n >> V\),说明有很多 \(d_i = 0\),这不会对转移产生影响,所以可以跳过。优化到 \(\Theta(nV\min\{n,V\})\)。

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

const int N = 10010;
const int M = 500010;

using lint = long long;

const lint linf = 0x3f3f3f3f3f3f3f3f;

lint f[M];

int n, val[N], p[N], V;

inline void tomin(lint& a, lint b) {
    b < a && (a = b);
}

signed main() {
    #ifndef XuYueming
    freopen("variance.in", "r", stdin);
    freopen("variance.out", "w", stdout);
    #endif
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%d", &val[i]), V = max(V, val[i]);
    for (int i = 1; i < n; ++i) p[i] = val[i + 1] - val[i];
    sort(p + 1, p + n);
    for (int i = 1; i < n; ++i) val[i] = val[i - 1] + p[i];
    memset(f, 0x3f, sizeof (lint) * (n * V + 5));
    f[0] = 0;
    for (int i = 1, mx = 0; i < n; ++i) {
        if (!p[i]) continue;
        for (int j = mx; j >= 0; --j) {
            if (f[j] == linf) continue;
            tomin(f[j + i * p[i]], f[j] + 2ll * j * p[i] + 1ll * i * p[i] * p[i]);
            tomin(f[j + val[i]], f[j] + 1ll * val[i] * val[i]);
            mx = max(mx, j + i * p[i]);
            mx = max(mx, j + val[i]);
            f[j] = linf;
        }
    }
    lint ans = linf;
    for (int i = 0; i <= n * V; ++i) {
        if (f[i] < linf)
            ans = min(ans, n * f[i] - 1ll * i * i);
    }
    printf("%lld", ans);
    return 0;
}

标签:geq,limits,方差,dfrac,sum,差分,题解,NOIP2021
From: https://www.cnblogs.com/XuYueming/p/18491480

相关文章

  • 题解:P10977 Cut the Sequence
    题目传送门分析看到这种题就可以想到动态规划,先设状态:$f_i$表示考虑前$i$个数,所需要的最小代价。发现$f_i$可以从所有$i$以前的状态加后一段区间转移过来,于是可以列出状态转移方程:$$f_i=\min_{j=i-1}^{s_i-s_j\leqm}(f_j+\max_{k=j+1}^i)$$其中$j$......
  • [题解]P2671 [NOIP2015 普及组] 求和
    P2671[NOIP2015普及组]求和可以发现我们对相同颜色且编号奇偶性相同的元素归为一组,组内的元素两两都满足题目条件,且这样可以不重不漏覆盖所有答案。设分完组之后,某一组内的元素编号分别是\(a_1,a_2,\dots,a_q\),数字分别是\(b_1,b_2,\dots,b_q\),则根据题意,该组的答案是:\[\lar......
  • 20241021 校测T1 致敬传奇捆绑测试题目(Perm) 题解
    题解:致敬传奇捆绑测试题目Perm来自不知道什么时候的回忆。给定正整数\(n\),一个\(1\simn\)的排列\(p\)是一个好排列,当且仅当使得对于任意\(1\lek<n\),都有\(\sum_{i=1}^kp_i>p_{k+1}\)。现在请你求出字典序第小的好排列\(p\)。\(1\len\le10^6\),\(1\lek\le......
  • [ARC133E] Cyclic Medians 题解
    一点不会套路。思路对于中位数相关,发现我们不好直接表示与中位数有关的内容。不妨枚举\(x\),把大于\(x\)的标为\(1\),小于等于\(x\)的标为\(0\),这样把所有最终为一的方案数加起来就是原来的答案。大概是这样一个东西:\[k=\sum_{i=0}^k[i<k]\]这个怎么求呢。发现若一组......
  • Public NOIP Round #7 T3 黑白棋子 题解
    Description有一棵\(n\)个点的树,顶点的编号为\(1\)到\(n\)。对于树中的每个顶点,可能存在一个白色的棋子、一个黑色的棋子,或者没有棋子。树上正好有\(w\)个白色棋子和\(b\)个黑色棋子。另外,对于每一对具有相同颜色棋子的顶点,存在一条路径,路径上的每个顶点都包含相同颜色......
  • AT_agc064_c [AGC064C] Erase and Divide Game 题解
    先考虑所有\(l_i=r_i\)时怎么做,可以建出反向Trie树,问题转化为从根开始每次向左子树或右子树走,第一个拿到空子树的人输,直接在Trie上dp即可。考虑从叶子层开始对每一层的点合并两个子树的dp值,发现每一层值相同的连续段是较少的。于是可以维护这些连续段,每次合并要将每个......
  • 洛谷P2596 [ZJOI2006] 书架 题解 splay tree 模板题
    题目链接:https://www.luogu.com.cn/problem/P2596主要涉及的操作就是:找到某一个编号的点(这个操作可以不用splaytree维护)删除某个点将某一个点插入到最前面,最后面,或者某一个位置查询前序遍历为\(k\)的节点编号因为每次删除都会又把这个点加回去,所以可以复用\(n\)个......
  • [题解]CF825E Minimal Labels
    LPhang为什么是神?思路显然可以想到一个错误的贪心:直接拓扑排序,每一次选择当前可以拓展的点中最小的元素进行编号。由于可能存在一个值较小的元素被藏在一个较大的元素后面,这种贪心就会出问题。出问题的本质原因就是我们希望字典序最小,就得使得越小的位置分配到更小的值。不妨......
  • 历年CSP-J初赛真题解析 | 2017年CSP-J初赛完善程序(27-36)
    学习C++从娃娃抓起!记录下CSP-J备考学习过程中的题目,记录每一个瞬间。附上汇总贴:历年CSP-J初赛真题解析|汇总_热爱编程的通信人的博客-CSDN博客(快速幂)请完善下面的程序,该程序使用分治法求x......
  • CF2023D Many Games 题解
    赛时被创四了。思路考虑我们什么时候合并会比原来优。例如,我们现在要合并\(p_1,w_1\)和\(p_2,w_2\),同时保证,\(w_1\gew_2\)。那么有:\[\frac{p_1}{100}\timesw_1\le\frac{p_1}{100}\times\frac{p_2}{100}\times(w_1+w_2)\]\[\frac{p_2}{100}\timesw_2\le\frac{p_1}{......