题目

给出一个长度为 \(n\) 的序列 \(A\) ;

你需要构造一个新的序列\(B\) ,满足:

  • $B_{i} \le B_{i+1} (1 \le i \lt n ) $
  • $\sum_{i=1}^{n} (A_i - B_i)^2 $ 最小

题解

  • 出题人和题解在这里 : http://15283746.blog.uoj.ac/blog/4966

  • 我只是整理了一下证明(Part 1)并套了一种做法(Part 2);

  • Part 1

  • 主要讨论最优的策略:

  • 引理一

    如果要求所有\(B_i\)相同等于\(x\),那么$x \ = \ \frac{\sum_{i=1}^{n} A_i }{n} $

    证明:写成关于\(x\)的二次函数即可证明;

  • 定理一

    ​ 答案一定是很多严格上升的等值段,即每一段的\(B\)相同,且等于这段\(A\)的平均值\(v(A)\) ;

    证明:由于相邻等值块的值严格不同,根据二次函数的性质,一定可以向靠近平均值的方向调整;

  • 引理二

    ​ 将任意一个序列延长之后,原序列对延长后的序列答案的贡献不小于原序列的最优答案;

    证明:由于是最优的所以显然,否则矛盾;

  • 引理三

    ​ 等值段的划分唯一;

    证明:

    ​ ( - _ -) 建立线性规划模型, $B_i \le B_{i+1} $ 这个不等式组在空间中的解是一个凸集,最优的点相当于和圆\((A_1,A_2,...,)\)的切点,感受一下可以知道是唯一的;

  • 定理二

    ​ 下列构造方法是最优的:

    ​ 维护一个以平均值为权值的单调栈,当加入一个点时,如果不满足单调性,则合并栈尾和当前区间,重复这个过程,最后将区间加入单调栈;

    证明:

    ​ 最优的划分为\(H[x,y]\) ,令如上策略的划分为\(H'[x,y]\) ,考虑归纳;

    ​ 假设对\(1 \le i \lt n\)均满足\(H=H'\) ,当\(i=n\)时:

    ​ 1.如果\(H'\)中含有两个及以上个等值块,可以划分两个长度<n的区间分别构造\(H_1'\)和\(H_2'\);

    ​ 根据引理二,可以知道一定是最优的;

    ​ 由构造方式这两个区间一定可以直接拼接且$H' = H_1' + H_2' $;

    ​ 2.如果\(H'\)中只有一个等值块,只需要证明任意大于1个等值块的\(H\)都不优即可;

    ​ 假设\(i\)是划分\(H\)的最后一个满足\(i\)和\(i+1\)不同块的点;

    ​ 考虑\(H'[1,i]\),设\(i\)在的块是\([j,i]\),在\(i+1\)到\(n\)之间一定存在第一个\(k\)合并了\([ j,i ]\)和\([i+1,k]\) ;

    ​ 由于$v[j,i] \lt v[i+1,n] \ , \ v[j,i] \ge v[i+1,k] $ ;

    ​ 所以$v[k+1,n] \gt v[j,i] \ge v[i+1,k] $ ;

    ​ 所以\(H'[1,k] + H'[k+1,n]\)一定合法且比\(H\)优;

  • 至此在不修改的时候可以 \(O(n)\) 解决问题;

  • Part 2

  • 考虑如何合并\([1,i-1 ]\)和\([i,i]\)和\([i+1,n]\),先讨论合并两个区间的情况;

  • 定理三

    ​ 两个区间的并的划分方案中任意一个划分点在子区间中也一定是划分点;

    从左到右执行,一定不会使左区间的划分点变多,从右往左同理,根据引理三得证,可以推广到多个区间的情况;

  • 根据引理三,设两个区间为\([1,mid]\)和\([mid+1,n]\),可以先处理出\(H'[1,mid-1]\)和\(H'[mid+1,n]\),根据定理三,为了方便修改意义区间元素直接是等值块,最终被合并的一定是左区间的一段后缀+右区间的一段前缀,令其为区间\([L_0,R_0]\),\(v[L_0,R_0]\) 表示区间平均值;

  • 引理四

    ​ 当加入到右区间的$ R \(时,设\) L_0 $是此时合并到的左端点,则:

    1.合法条件为:$v[L_0,R] \gt v_{L0-1} $ ,且具有可二分性;

    2.\(L_0\)是使得\(v[L,R]\)最大的\(L\);

    证明:

    ​ 由于栈是单增的并且在合并过程中,加入点的权值的变化是单调不增的,所以12得证;

  • 定理四

    ​ 对于右边的一个等值块\(R\),\(L\)是其在引理四中的\(L_0\),若:

    1.\(R<R_0\) 则有\(v[L,R] \ge v_{R+1}\) ;

    2.\(R \ge R_0\) 则有\(v[L,R] \lt v_{R+1}\) ;

    证明:

    ​ 由于\(R_0\)一定满足2,只需要证明对于一个满足的\(R\),\(>R\)的位置一定满足2即可;

    归纳假设\(R\)满足,左端点设为\(L\),对于\(R+1\),左端点设为\(L'\),有引理四2和假设得到:\(v[L',R] \le v[L,R] \lt v_{R+1}\),所以$v[L',R+1] \lt v_{R+1} \lt v_{R+2} $ ,得证;

  • 引理四和定理四在中间有一个修改点 \(i\) 的时候依旧适用;

  • 所以可以找出[1,i-1]的单调和[i+1,n]的单调栈(从n做到1再往后退栈),二分套二分即可;

#include<bits/stdc++.h>
#define ll long long
#define mod 998244353
using namespace std;
const int N=100010;
int n,m,ny[N],pl,pr,len[N],ansl[N],ansr[N],pre[N],ql,qr,ans[N];
struct query{
int x,y,id;
query(int _x=0,int _y=0,int _id=0):x(_x),y(_y),id(_id){};
bool operator <(const query&A)const{return x<A.x;}
}Q[N];
struct data{
ll x,y,z;
data(ll _x=0,ll _y=0,ll _z=0):x(_x),y(_y),z(_z){};
data operator +(const data&A)const{return data(x+A.x,y+A.y,z+A.z);}
data operator -(const data&A)const{return data(x-A.x,y-A.y,z-A.z);}
bool operator <=(const data&A)const{return y*A.x<=A.y*x;}
bool operator >=(const data&A)const{return y*A.x>=A.y*x;}
}A[N],L[N],R[N],pR[N],sL[N],sR[N],psR[N],X,Y,Z;
data getL(int l,int r){return sL[r]-sL[l-1];}
data getR(int l,int r){return sR[r]-sR[l-1];}
int cal(data now){
int x=now.x,y=now.y%mod,z=now.z%mod;
int v=(ll)y*ny[x]%mod;
return (z-(ll)v*y*2%mod+(ll)v*v%mod*x%mod+mod)%mod;
}
void lowerL(){
int l=1,r=pl+1;
while(l<r){
int mid=(l+r+1)>>1;
Z=Y+getL(mid,pl);
if(Z<=L[mid-1])r=mid-1;
else l=mid;
}
Z=Y+getL(ql=l,pl);
}
void lowerR(){
int l=1,r=pr+1;
while(l<r){
int mid=(l+r+1)>>1;
Y=X+getR(mid,pr);
lowerL();
if(Z>=R[mid-1])r=mid-1;
else l=mid;
}
Y=X+getR(qr=r,pr);
lowerL();
}
int main(){
// freopen("sequence.in","r",stdin);
// freopen("sequence.out","w",stdout);
scanf("%d%d",&n,&m);ny[1]=1;
for(int i=2;i<=n;++i){ny[i]=1ll*(mod-mod/i)*ny[mod%i]%mod;}
for(int i=1;i<=n;++i){
int x;scanf("%d",&x);
A[i]=data(1,x,(ll)x*x%mod);
}
for(int i=1;i<=m;++i){
int x,y;scanf("%d%d",&x,&y);
Q[i]=query(x,y,i);
}
sort(Q+1,Q+m+1);
L[0]=data(1,0,0);
R[0]=data(1,1e9+1,0);
for(int i=n;~i;--i){
data now=A[i];
while(now>=R[pr])now=now+R[pr--];
len[i]=++pr;
pR[i]=R[pr];R[pr]=now;
psR[i]=sR[pr];sR[pr]=sR[pr-1]+now;
pre[i]=ansr[pr];ansr[pr]=(ansr[pr-1]+cal(now))%mod;
}
ans[0]=ansr[pr];
for(int i=1,tl=0,tr=1;i<=m;++i){
while(tr<Q[i].x+1){
R[pr]=pR[tr];
sR[pr]=psR[tr];
ansr[pr]=pre[tr];
pr=len[++tr];
}
while(tl<Q[i].x-1){
data now=A[++tl];
while(now<=L[pl])now=L[pl--]+now;
L[++pl]=now;
sL[pl]=sL[pl-1]+now;
ansl[pl]=(ansl[pl-1]+cal(now))%mod;
}
X=data(1,Q[i].y,(ll)Q[i].y*Q[i].y%mod);
lowerR();
ans[ Q[i].id ] = ((ll)ansl[ql-1] + ansr[qr-1] + cal(Z)) %mod;
}
for(int i=0;i<=m;++i)printf("%d\n",ans[i]);
return 0;
}

【loj3059】【hnoi2019】序列的更多相关文章

  1. 【洛谷5294】[HNOI2019] 序列(主席树维护单调栈+二分)

    点此看题面 大致题意: 给你一个长度为\(n\)的序列\(A\),每次询问修改一个元素(只对当前询问有效),然后让你找到一个不下降序列\(B\),使得这两个序列相应位置之差的平方和最小,并输出这个最小 ...

  2. 【题解】Luogu P5294 [HNOI2019]序列

    原题传送门 题意:给你一个长度为\(n\)的序列\(A\),每次询问修改一个元素(只对当前询问有效),然后让你找到一个不下降序列\(B\),使得这两个序列相应位置之差的平方和最小,并输出这个最小平方和 ...

  3. 【Luogu5294】[HNOI2019]序列

    题目链接 题意 给定一个序列,要求将它改造成一个非降序列,修改一个数的代价为其改变量的平方. 最小化总代价. 另有\(Q\) 次询问,每次修改一个位置上的数.(询问之间独立,互不影响) Sol 神仙 ...

  4. [HNOI2019]序列(单调栈+二分)

    通过打表证明发现答案就是把序列划分成若干段,每段的b都是这一段a的平均数.50分做法比较显然,就是单调栈维护,每次将新元素当成一个区间插入末尾,若b值不满足单调不降,则将这个区间与单调栈前一个区间合并 ...

  5. 题解 [HNOI2019]序列

    题目传送门 题目大意 给出一个\(n\)个数的数列\(A_{1,2,...,n}\),求出一个单调不减的数列\(B_{1,2,...,n}\),使得\(\sum_{i=1}^{n}(A_i-B_i)^ ...

  6. luogu P5294 [HNOI2019]序列

    传送门 这个什么鬼证明直接看uoj的题解吧根本不会证明 首先方案一定是若干段等值的\(B\),然后对于一段,\(B\)的值应该是\(A\)的平均值.这个最优方案是可以线性构造的,也就是维护以区间平均值 ...

  7. CSP-S2019「Symphony」

    NOTICE:如觉得本文有什么错误或不妥之处,欢迎评论区以及私信交流,反对乱喷,如有一些让人不爽的评论或人身攻击,带来的后果本人一律不负责 准备工作 Day-inf~Day-3 000 every d ...

  8. Loj #3059. 「HNOI2019」序列

    Loj #3059. 「HNOI2019」序列 给定一个长度为 \(n\) 的序列 \(A_1, \ldots , A_n\),以及 \(m\) 个操作,每个操作将一个 \(A_i\) 修改为 \(k ...

  9. LOJ 3059 「HNOI2019」序列——贪心与前后缀的思路+线段树上二分

    题目:https://loj.ac/problem/3059 一段 A 选一个 B 的话, B 是这段 A 的平均值.因为 \( \sum (A_i-B)^2 = \sum A_i^2 - 2*B \ ...

随机推荐

  1. linux安装mysql后报错启动不了Starting MySQL. ERROR! The server quit without updating PID file (/var/lib/mysql/localhost.localdomain.pid).

    今天安装完Mysql后,开启发生了错误: 2.打开错误信息文件,查看错误原因是:Plugin 'FEDERATED' is disabled. /usr/sbin/mysqld: Table 'mys ...

  2. HTML页面导出PDF——高清版

    需要做一个导出PDF的功能,网上找有很多,但是一般导出来的都是比较模糊的那种,下面这个是高清版的,导出的PDF都是几M,跟正常手动导出的差不多,很清晰. 首先用到的JS有: <script ty ...

  3. 3.将模型添加到 ASP.NET Core MVC 应用

    添加数据模型类 右键单击 Models 文件夹,然后单击“添加” > “类”. 将类命名“Movie”.向 Movie 类添加以下属性: using System;using System.Co ...

  4. Linq实现分组后取最大(小)值

    var beatles = (new[] { new { inst = "张三" , age="50" }, new { inst = "张三&quo ...

  5. centos7划分vlan

    1. lsmod|grep 8021q  确认内核是够载入了802.1q模组 2.modprobe -a 8021q   如果没载入使用这个命令载入模组 3.配置vlan需要vconfig命令,由于c ...

  6. 【android,eclipse解决】eclipse insert "}" to complete ClassBodyR.java

    Android开发:eclipse搭建后,如果出现 eclipse insert "}" to complete ClassBodyR.java/appcompat_v7/gen/ ...

  7. 前端动态效果小结(jQuery)

    1.easyUI(jQuery) http://www.jeasyui.net/demo/954.html

  8. JavaScript 解决 url 中的中文乱码问题

    页面传值过程中,通过 url 传值,发现中文会乱码. 以下是解决方法: 1.传的页面: encodeURI(url + "?userName=" + userName); //en ...

  9. 17,Flask-admin后台管理系统总结

    导入包 from flask_admin import Admin,BaseView,expose,AdminIndexView from flask_admin.contrib.sqla impor ...

  10. Sonar中的坏习惯详解

    22种代码的坏味道,一句话概括: 如果一段代码是不稳定或者有一些潜在问题的,那么代码往往会包含一些明显的痕迹. 正如食物要腐坏之前,经常会发出一些异味一样. 我们管这些痕迹叫做“代码异味”. 参考资料 ...