LGP7962 [NOIP 2021] 方差 学习笔记

LGP7962 [NOIP 2021] 方差 学习笔记

\(\texttt{Luogu Link}\)

前言

对于当前(指 \(\texttt{20250903}\))的我来说,大概改制后 \(\texttt{NOIP}\) 的真题里面,过了这个村就没这个店(离人类还比较接近的题)了。

假设这里有一张图片,展示了洛谷题库,通过标签筛选了 \(\texttt{NOIP}\)\(\texttt{2020}\) 改制后的二十四道题,其中大多数题目都已通过。然而,“比赛”、“移球游戏”、“密码锁”、“棋局”均无提交,“喵了个喵”、“微信步数”状态显示为红叉。除此之外,还有“排水系统”和“字符串匹配”因为涉及算法原因没写。

本文参考WeLikeStudying的题解

题意简述

你有一个长度为 \(n\) 的单调不降的正整数序列 \(A\)。你可以任意次进行这样的操作:选择一个下标 \(1<i<n\),使 \(a_i\gets a_{i-1}+a_{i+1}-a_i\)。问该数列在操作后的方差的最小值是多少。输出它乘以 \(n^2\) 的结果。

\(n\le 10^4\)\(a_i\le 600\)

做法解析

从哪入手呢?一点点分析下题面。

看到这么多限制就要想结论。

首先关于方差有个经典结论:设 \(\overline{x^2}\)\(a_1^2,a_2^2,\cdots ,a_n^2\) 的平均值,\(\overline{x}\)\(a_1,a_2,\cdots,a_n\) 的平均值,则 \(s^2=\overline{x^2}-\overline{x}^2\)

然后看看这个不太说人话的操作,仔细观察,实际上就是在交换差分数组 \(b_i=a_{i+1}-a_i\) 的相邻两项。

再想想方差本身是啥:“方差是和中心偏离的程度,用来衡量一批数据的波动大小”。于是我们思考,数据会长什么样子,使得它趋近于某个值。鉴于 \(A\) 单调不降,我们很快发现,当差分数组呈单谷状时 \(A\) 的方差大概最小。换句话说,方差最小时 \(B\) 肯定是单谷的,需要解决的问题在于 \(B\) 数组里的元素要怎么分到谷的两侧。

pVg0VWq.png

实际上这可以严谨推导证明,参考洛谷某高赞题解这篇式子没那么大块的题解,读者自证不难。

现在就是 \(\texttt{DP}\) 的事了。我们要 \(\texttt{DP}\) 什么呢?

你已经知道了 \(s^2=\overline{x^2}-\overline{x}^2\)。而题目要你输出 \(s^2\times n^2\),也就是我们直接求最小化 \(n\times(\sum a_i^2)-(\sum a_i)^2\)。可见我们的答案取决于 \(\sum a_i^2\)\(\sum a_i\)(废话),那么我们把一个写进 \(\texttt{DP}\) 的维度里,另一个作为 \(\texttt{DP}\) 求的东西即可。

于是我们很自然地设 \(f_{i,x}\) 为考虑了差分数组 \(B\) 的前 \(i\) 个元素,\(\sum a_i=x\)\(\sum a_i^2\) 的最小值。

转移就呼之欲出了。我们往谷底左边插元素即有:\(f_{i-1,x}+i\times b_i^2+2x\cdot b_i\to f_{i,x+b_i\times i}\),往谷底右边插元素即有:\(f_{i-1,x}+(\sum_{j=1}^i b_j)^2 \to f_{i,x+\sum_{j=1}^i b_j}\)。相信你可以轻松理解。

然后这东西显然能滚动数组。时间复杂度 \(O(n\times n\times a)\),然后……超时了?

实际上,对于 \(B\) 数组来说,最多有 \(\max a_i\) 个差分值是非 \(0\) 的,原因显然。我们提前把那些 \(0\) 处理一下即可,详情见代码。

时间复杂度 \(O(n\times\min(n,a)\times a)\)。可以通过。

代码实现

#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=1e4+5,MaxV=6e6+5,Inf=0x7fffffff;
int N,mxa,A[MaxN],B[MaxN],bsum[MaxN],zcnt,V,ci,pi;
int dp[2][MaxV],ans=Inf;
int main(){
    readi(N);
    for(int i=1;i<=N;i++)readi(A[i]),maxxer(mxa,A[i]);
    for(int i=1;i<N;i++)B[i]=A[i+1]-A[i];
    sort(B+1,B+N);V=mxa*N,ci=0,pi=1;
    for(int i=1;i<N;i++)bsum[i]=bsum[i-1]+B[i],zcnt+=(!B[i]);
    dp[ci][0]=0;for(int x=1;x<=V;x++)dp[ci][x]=Inf;
    for(int i=zcnt+1;i<N;i++){
        ci^=1,pi^=1;
        for(int x=0;x<=V;x++)dp[ci][x]=Inf;
        for(int x=0;x<=V;x++){
            if(dp[pi][x]==Inf)continue;
            minner(dp[ci][x+B[i]*i],dp[pi][x]+i*B[i]*B[i]+2*x*B[i]);
            minner(dp[ci][x+bsum[i]],dp[pi][x]+bsum[i]*bsum[i]);
        }
    }
    for(int i=0;i<=V;i++)if(dp[ci][i]!=Inf)minner(ans,N*dp[ci][i]-i*i);
    writil(ans);
    return 0;
}

后记

\(\texttt{UPD on 20251014}\)

现在,“移球游戏”、“密码锁”、“棋局”、“喵了个喵”、“微信步数”、“排水系统”均已通过。改制后省级联赛的题目中,只有“比赛”保持着红叉,“字符串匹配”暂无提交。继续加油!

posted @ 2025-09-03 19:44  矞龙OrinLoong  阅读(6)  评论(0)    收藏  举报