原题传送门

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

观察样例说明,发现一个很有趣的性质,\(B\)中数字相同的一段的数字正好是\(A\)中这段数字的平均数

那我们就珂以猜想:最优解的形式一定为分成若干段,每一段的\(B_i\)即取其中\(A_i\)的平均数,同时保证\(B\)的有序性(这篇论文好像有证明)

如何求出最优的\(B\)?我们珂以使用单调栈

考虑枚举\(i\),将\([i,i]\)塞进单调栈中,然后比较栈顶区间的平均值和栈顶下面一个区间的平均值。如果栈顶区间平均值较小,则不满足不下降性质,因此我们将这两个区间合并,然后继续与再下面一个区间进行比较……

如何合并答案?我们只需要维护维护区间元素个数,区间元素和,区间元素平方和即可(像方差那题一样)

接下来考虑如何修改。我们在求整个序列的最优解时,同主席树维护\(A\)每个前缀的单调栈\(pre\)。类似的,从后向前也跑一次,用主席树维护\(A\)每个后缀的单调栈\(suf\)。

假设我们将位置\(pos\)的值修改成了\(val\)。设修改后最优解中\(pos\)所在的区间为\([L,R]\),如果我们能够快速求出\(L,R\)我们就珂以快速得出答案。

注意到单调栈中的一段数的任何前缀平均值都大于去掉该前缀剩余的数的平均值,所以\(L\)为\(pre[pos-1]\)中某个区间的\(L\)或\(pos\),\(R\)为\(suf[pos+1]\)中某个区间的\(R\)或\(pos\)

二分\(R\)的位置,在主席树\(pre[pos-1]\)上二分求出符合的\(L\),判断是否合法。最终找到最小的合法的\(R\),算出\(L\),就珂以求出答案了

#include <bits/stdc++.h>
#define N 100005
#define ll long long
#define mod 998244353
#define getchar nc
using namespace std;
inline char nc(){static char buf[100000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{register int x=0,f=1;register char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;
}
inline void write(register int x)
{if(!x)putchar('0');if(x<0)x=-x,putchar('-');static int sta[20];register int tot=0;while(x)sta[tot++]=x%10,x/=10;while(tot)putchar(sta[--tot]+48);
}
inline int Max(register int a,register int b)
{return a>b?a:b;
}
int n,m,pre[N],prelen[N],suf[N],suflen[N],tot;
pair<int,int> s[N];
ll inv[N];
struct node{ll x,y,z;node(){x=y=z=0;}node(register ll _x,register ll _y,register ll _z){x=_x,y=_y,z=_z;}inline ll cal(){return (z+mod-(y%mod)*(y%mod)%mod*inv[x]%mod)%mod;}
}sum[N];
inline node Init(register ll v)
{return node(1,v,v*v%mod);
}
inline node operator + (node a,node b){return (node){a.x+b.x,a.y+b.y,(a.z+b.z)%mod};}
inline node operator - (node a,node b){return (node){a.x-b.x,a.y-b.y,(a.z-b.z+mod)%mod};}
inline bool operator < (node a,node b){if(!a.x)return b.x;if(!b.x)return 0;return (double)a.y/a.x<(double)b.y/b.x;
}
inline node cal(register int l,register int r)
{if(!l&&!r)return node(0,0,0);return sum[r]-sum[l-1];
}
struct seg{int ls,rs,L,R,ans,Rp;inline void merge(register seg a,register seg b){L=a.L;R=Max(a.R,b.R);ans=(a.ans+b.ans)%mod;Rp=a.Rp;}
}tr[N*80];
inline void modify(register int &x,register int l,register int r,register int pos,register int L,register int R)
{tr[++tot]=tr[x];x=tot;if(l==r)tr[x]=(seg){0,0,L,R,cal(L,R).cal(),R};else{int mid=l+r>>1;if(pos<=mid)modify(tr[x].ls,l,mid,pos,L,R);elsemodify(tr[x].rs,mid+1,r,pos,L,R);tr[x].merge(tr[tr[x].ls],tr[tr[x].rs]);}
}
inline int query_suf(register int x,register int l,register int r,register int pos)
{if(l==r)return tr[x].R;int mid=l+r>>1;if(pos<=mid)return query_suf(tr[x].ls,l,mid,pos);elsereturn query_suf(tr[x].rs,mid+1,r,pos);
}
inline int query_pre(register int x,register int l,register int r,register int pos,register node &val)
{if(r<=pos){node twh=cal(tr[x].L,tr[x].R),tlf=cal(tr[x].L,tr[x].Rp);if(!(tlf<val+twh)){val=val+twh;return 0;}if(l==r)return tr[x].R;}int mid=l+r>>1,res=0;if(pos>mid)res=query_pre(tr[x].rs,mid+1,r,pos,val);if(res)return res;return query_pre(tr[x].ls,l,mid,pos,val);
}
int main()
{n=read(),m=read();inv[1]=1;for(register int i=2;i<=n;++i)inv[i]=inv[mod%i]*(mod-mod/i)%mod;for(register int i=1;i<=n;++i)sum[i]=sum[i-1]+Init(read());for(register int i=1,top=0;i<=n;++i){pre[i]=pre[i-1];int l=i;while(top&&!(cal(s[top].first,s[top].second)<cal(l,i)))modify(pre[i],1,n,top,0,0),l=s[top--].first;s[prelen[i]=++top]=make_pair(l,i);modify(pre[i],1,n,top,l,i);}for(register int i=n,top=0;i;--i){suf[i]=suf[i+1];int r=i;while(top&&!(cal(i,r)<cal(s[top].first,s[top].second)))modify(suf[i],1,n,top,0,0),r=s[top--].second;s[suflen[i]=++top]=make_pair(i,r);modify(suf[i],1,n,top,i,r);}write(tr[pre[n]].ans),puts("");while(m--){int x=read(),y=read();int l=0,r=suflen[x+1]-1,res=r+1;while(l<=r){int mid=l+r>>1;int rp=mid?query_suf(suf[x+1],1,n,suflen[x+1]-mid+1):x;node val=Init(y)+cal(x+1,rp);int lp=x>1?query_pre(pre[x-1],1,n,prelen[x-1],val):1;if(val<cal(rp+1,query_suf(suf[x+1],1,n,suflen[x+1]-mid)))res=mid,r=mid-1;elsel=mid+1;}int rp=res?query_suf(suf[x+1],1,n,suflen[x+1]-res+1):x;node val=Init(y)+cal(x+1,rp);int lp=x>1?query_pre(pre[x-1],1,n,prelen[x-1],val):1;write((val.cal()+tr[pre[lp]].ans+tr[suf[rp+1]].ans)%mod),puts("");}return 0;
}

转载于:https://www.cnblogs.com/yzhang-rp-inf/p/10960923.html

【题解】Luogu P5294 [HNOI2019]序列相关推荐

  1. 题解 luogu P2568 GCD

    题解 luogu P2568 GCD 时间:2019.3.11 欧拉函数+前缀和 题目描述 给定整数\(N\),求\(1\le x,y \le N\)且\(\gcd(x,y)\)为素数的数对\((x, ...

  2. PAT甲级1086 Tree Traversals Again:[C++题解]二叉树中序序列、栈、求后序遍历

    文章目录 题目分析 题目链接 题目分析 分析: 给定栈模拟的二叉树的中序序列. 我们可以发现一些性质: 1 第一个值是根结点. 2 对于所有的push操作,如果上一个是push,该结点就是上一个结点的 ...

  3. Luogu P3321 [SDOI2015]序列统计

    [SDOI2015]序列统计 题目描述 小C有一个集合\(S\),里面的元素都是小于\(M\)的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为\(N\)的数列,数列中的每个数都属于集合\( ...

  4. #loj3059 HNOI2019 序列

    据说是保序回归问题? 业界都在用的算法是将序列分成若干段,然后每段取个平均值生成一个不降的b序列 至于为啥是对的?我也不知道啊 一开始想写个主席树 然后懒癌发作选择了反复二分的咸鱼做法 先考虑50分怎 ...

  5. 计蒜客题解——T1244:单词序列

    题目相关 题目链接 计蒜客 OJ,https://nanti.jisuanke.com/t/T1244. 我的 OJ,http://47.110.135.197/problem.php?id=4766 ...

  6. luogu P5292 [HNOI2019]校园旅行

    传送门 首先考虑暴力M^2dp,考虑回文串是可以从回文中心每次在两边拓展的,设\(f_{i,j}\)为\(i\)到\(j\)的路径是否是回文串,bfs转移,枚举两点出边,如果两个新端点颜色相同就更新 ...

  7. luogu P2572 [SCOI2010]序列操作

    传送门 这个题我写了差不多一周吧-- 终于改成了一个能在考试的时候写完的版本 大量的区间操作 1e5 显然线段树解决 确实是板子题 但是极其难调-- 最后听rabbithu学姐讲了一下才用" ...

  8. luogu P5286 [HNOI2019]鱼

    传送门 这题真的牛皮,还好考场没去刚( 这题口胡起来真的简单 首先枚举D点,然后对其他所有点按极角排序,同时记录到D的距离.然后按照极角序枚举A,那么鱼尾的两个点的极角范围就是A关于D对称的那个向量, ...

  9. Luogu P2572 [SCOI2010]序列操作 线段树。。

    咕咕了...于是借鉴了小粉兔的做法ORZ... 其实就是维护最大子段和的线段树,但上面又多了一些操作....QWQ 维护8个信息:1/0的个数(sum),左/右边起1/0的最长长度(ls,rs),整段 ...

  10. 学习手记(2021/3/19~?)

    上一篇有点多就开新的了 文章目录 树哈希 wqswqswqs二分 单位根反演 威佐夫博弈 范德蒙德行列式 BEST定理 平面图欧拉定理 FWT转移矩阵的推导 保序回归 一些数学小结论 范德蒙德卷积 乘 ...

最新文章

  1. 【原创】CSSOO的思想及CSS框架的应用(未整理完)
  2. 深入理解python的元组本身不可变性
  3. 动态瑜伽 静态瑜伽 初学者_瑜伽与编程有什么关系?
  4. 2018年秋计算机应用基础本科,广东开放大学远程教育专科2018年秋计算机应用基础Word模块测试...
  5. python探测端口_Python实现端口检测
  6. 利用nexus搭建maven库并利用AS上传aar
  7. mysql redo/binlog 放在ssd盘或SAS盘性能差异测试
  8. php redis地址和端口号,redis默认端口是什么
  9. 一支手可以代表多大的数呢? 2 的 19 次方。
  10. 荣耀8青春版android,华为荣耀8青春版有几个版本?荣耀8青春版低配版/标准版/高配版区别对比评测...
  11. FPGA——PS/2驱动
  12. 洛谷题单···(Python)
  13. (详细)《美国节日》:某月的第几个星期几
  14. 银行信用卡办卡申请进度查询API接口地址
  15. 2021南昌二中高考成绩查询,2020年南昌各大高中高考喜报合集!
  16. 在VisualStudio中使用EF操作Firebird数据库
  17. 【专业英语】计算机英语词汇Day6
  18. GD32实战11__SPI FLASH
  19. Technodigit.3DReshaper.Meteor.v2017.MR1.Win64 1CD
  20. win32api模拟键盘鼠标

热门文章

  1. java 云 代码_我 - java代码库 - 云代码
  2. android 获取录音时长_Android中集成FFmpeg ③执行进度
  3. 【浙江省第16届省赛E:】Sequence in the Pocket(思维--不模拟复杂过程)
  4. ttysac1 java_ttySAC0与/dev/tts/0是否对应同一个物理设备串口0
  5. java string 匹配次数_Java实现统计某字符串在另一个字符串中出现的次数
  6. vc mysql ado blob_在VC下采用ADO实现BLOB(Binary)数据的存储,读取,修改,删除。...
  7. 台式计算机m9870t,新闻中心 ——驱动之家:您身边的电脑专家
  8. java int integer_浅谈java中int和Integer的区别
  9. libuv 原理_nodejs如何利用libuv实现事件循环和异步
  10. 图像频域增强:傅里叶变换