luogu P5294 [HNOI2019]序列
传送门
这个什么鬼证明直接看uoj的题解吧根本不会证明
首先方案一定是若干段等值的\(B\),然后对于一段,\(B\)的值应该是\(A\)的平均值.这个最优方案是可以线性构造的,也就是维护以区间平均值为权值的单调栈,每次在后面插入一个元素,不断弹栈并与最后一个合并,直到平均值单调递增
然后这个单调栈是可以两个区间的单调栈直接合并的,因为合并完后新单调栈的断点集合是原来两段的断点集合的子集.合并直接暴力就好了合并的话一定是前面那个的一段后缀的后面的一段前缀合并,然后后面的前缀位置(就是合并区间的右端点)是可以二分的,然后二分左端点使得合并的区间平均值最大,然后如果这个平均值比右端点右边的那一块的平均值小,那么最优的右端点就在在这个右端点以及其左边,否则在右边
然后用个可持久化线段树预处理一下每个前缀和后缀的单调栈就行了,注意从后往前和从前往后做都是一样的,能得到最优解
以上都是蒯的题解qwq,感性理解一下?
// luogu-judger-enable-o2
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<ctime>
#include<queue>
#include<map>
#include<set>
#define LL long long
#define db long doubleusing namespace std;
const int N=1e5+10,mod=998244353;
const db eps=1e-10;
int rd()
{int x=0,w=1;char ch=0;while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}return x*w;
}
int fpow(int a,int b){int an=1;while(b){if(b&1) an=1ll*an*a%mod;a=1ll*a*a%mod,b>>=1;} return an;}
int inv(int a){return fpow(a,mod-2);}
LL sm[N*85],rsm[N*85];
int n,m,st[N],tp,a[N],ps1[N],ps2[N],an[N*85],nm[N*85],rnm[N*85],ch[N*85][2],len1[N],len2[N],rt1[N],rt2[N],tt;
LL sta[N][2];
void inst(int o1,int o2,int x,int ll,int rr,LL ns,int nn)
{int l=1,r=n,tl=0;while(l<r){st[++tl]=o1;int mid=(l+r)>>1;if(x<=mid){ch[o1][0]=++tt,ch[o1][1]=ch[o2][1];o1=ch[o1][0],o2=ch[o2][0];r=mid;}else{ch[o1][0]=ch[o2][0],ch[o1][1]=++tt;o1=ch[o1][1],o2=ch[o2][1];l=mid+1;}}sm[o1]=rsm[o1]=ns,nm[o1]=rnm[o1]=nn;int ax=1ll*ns%mod*inv(nn%mod)%mod;an[o1]=nn?(1ll*(ps2[rr]-ps2[ll-1]+mod)%mod+1ll*ax*ax%mod*nn%mod-2ll*(ps1[rr]-ps1[ll-1]+mod)%mod*ax%mod)%mod:0;an[o1]+=an[o1]<0?mod:0;while(tl){int o=st[tl--];sm[o]=sm[ch[o][0]]+sm[ch[o][1]],nm[o]=nm[ch[o][0]]+nm[ch[o][1]],an[o]=(an[ch[o][0]]+an[ch[o][1]])%mod;rsm[o]=rsm[ch[o][1]],rnm[o]=rnm[ch[o][1]];}
}
struct node
{LL x;int y;node(){x=y=0;}node(LL ns,int nn){x=ns,y=nn;}node operator + (const node &bb) const {return node(x+bb.x,y+bb.y);}
};
node quer(int o,int l,int r,int ll,int rr)
{if(ll>rr||!o) return node(0,0);if(ll<=l&&r<=rr) return node(sm[o],nm[o]);int mid=(l+r)>>1;node an;if(ll<=mid) an=an+quer(ch[o][0],l,mid,ll,rr);if(rr>mid) an=an+quer(ch[o][1],mid+1,r,ll,rr);return an;
}
node quer(int o,int l,int r,int lx)
{if(!o) return node(0,0);if(l==r) return node(sm[o],nm[o]);int mid=(l+r)>>1;if(lx<=mid) return quer(ch[o][0],l,mid,lx);return quer(ch[o][1],mid+1,r,lx);
}
int getan(int o,int l,int r,int ll,int rr)
{if(ll>rr||!o) return 0;if(ll<=l&&r<=rr) return an[o];int mid=(l+r)>>1,an=0;if(ll<=mid) an+=getan(ch[o][0],l,mid,ll,rr);if(rr>mid) an+=getan(ch[o][1],mid+1,r,ll,rr);return an%mod;
}
int cmp(LL s1,LL n1,LL s2,LL n2)
{s1*=n2,s2*=n1;if(s1==s2) return 0;return s1>s2?1:-1;
}
int nl;
node querl(int o,node aa)
{node an;int l=1,r=n;while(l<r){int mid=(l+r)>>1;node ar=aa+an+node(sm[ch[o][1]],nm[ch[o][1]]),al=node(rsm[ch[o][0]],rnm[ch[o][0]])+ar;if(cmp(al.x,al.y,ar.x,ar.y)<0) o=ch[o][1],l=mid+1;else an=an+node(sm[ch[o][1]],nm[ch[o][1]]),o=ch[o][0],r=mid;}node ar=aa+an,al=node(sm[o],nm[o])+ar;if(cmp(al.x,al.y,ar.x,ar.y)>0) an=an+node(sm[o],nm[o]);nl=l;return an;
}int main()
{n=rd(),m=rd();for(int i=1;i<=n;++i){a[i]=rd();ps1[i]=(ps1[i-1]+a[i])%mod;ps2[i]=(ps2[i-1]+1ll*a[i]%mod*a[i]%mod)%mod;}for(int i=1;i<=n;++i){int las=tp;sta[++tp][0]=a[i],sta[tp][1]=1;while(tp>1&&cmp(sta[tp-1][0],sta[tp-1][1],sta[tp][0],sta[tp][1])>=0)sta[tp-1][0]+=sta[tp][0],sta[tp-1][1]+=sta[tp][1],--tp;rt1[i]=rt1[i-1];for(int j=las;j>=tp;--j){int la=rt1[i];inst(rt1[i]=++tt,la,j,j,j,0,0);}int la=rt1[i];inst(rt1[i]=++tt,la,tp,i-sta[tp][1]+1,i,sta[tp][0],sta[tp][1]);len1[i]=tp;}tp=0;for(int i=n;i;--i){int las=tp;sta[++tp][0]=a[i],sta[tp][1]=1;while(tp>1&&cmp(sta[tp-1][0],sta[tp-1][1],sta[tp][0],sta[tp][1])<=0)sta[tp-1][0]+=sta[tp][0],sta[tp-1][1]+=sta[tp][1],--tp;rt2[i]=rt2[i+1];for(int j=las;j>=tp;--j){int la=rt2[i];inst(rt2[i]=++tt,la,j,j,j,0,0);}int la=rt2[i];inst(rt2[i]=++tt,la,tp,i,i+sta[tp][1]-1,sta[tp][0],sta[tp][1]);len2[i]=tp;}printf("%d\n",an[rt1[n]]);while(m--){int x=rd(),y=rd();int l=1,r=len2[x+1],z=0;while(l<=r){int mid=(l+r)>>1;node a1=quer(rt2[x+1],1,n,mid,len2[x+1])+node(y,1),a2=mid>1?quer(rt2[x+1],1,n,mid-1):node(1e14,1);if(cmp(a1.x,a1.y,a2.x,a2.y)<0) z=mid,l=mid+1;else r=mid-1;}int z1=len1[x-1]+1,z2=0;l=1,r=z+1;while(l<=r){int mid=(l+r)>>1;node a1=quer(rt2[x+1],1,n,mid,len2[x+1])+node(y,1);node a2=querl(rt1[x-1],a1),a3=mid>1?quer(rt2[x+1],1,n,mid-1):node(1e14,1);if(cmp((a1+a2).x,(a1+a2).y,a3.x,a3.y)<0) z1=nl,z2=mid,l=mid+1;else r=mid-1;}node a1=quer(rt1[x-1],1,n,z1,len1[x-1]),a2=quer(rt2[x+1],1,n,z2,len2[x+1]),aa=a1+a2+node(y,1);int ll=x-a1.y,rr=x+a2.y,ax=1ll*aa.x%mod*inv(aa.y%mod)%mod;int ans=(((1ll*ps2[rr]-ps2[ll-1]-1ll*a[x]*a[x]+1ll*y*y)%mod+mod)%mod+1ll*ax*ax%mod*(rr-ll+1)%mod-2ll*(1ll*ps1[rr]-ps1[ll-1]-a[x]+y+mod+mod)%mod*ax%mod)%mod;ans+=ans<0?mod:0;printf("%lld\n",(1ll*ans+getan(rt1[x-1],1,n,1,z1-1)+getan(rt2[x+1],1,n,1,z2-1))%mod);}return 0;
}
转载于:https://www.cnblogs.com/smyjr/p/10713361.html
luogu P5294 [HNOI2019]序列相关推荐
- Luogu P3321 [SDOI2015]序列统计
[SDOI2015]序列统计 题目描述 小C有一个集合\(S\),里面的元素都是小于\(M\)的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为\(N\)的数列,数列中的每个数都属于集合\( ...
- #loj3059 HNOI2019 序列
据说是保序回归问题? 业界都在用的算法是将序列分成若干段,然后每段取个平均值生成一个不降的b序列 至于为啥是对的?我也不知道啊 一开始想写个主席树 然后懒癌发作选择了反复二分的咸鱼做法 先考虑50分怎 ...
- luogu P5292 [HNOI2019]校园旅行
传送门 首先考虑暴力M^2dp,考虑回文串是可以从回文中心每次在两边拓展的,设\(f_{i,j}\)为\(i\)到\(j\)的路径是否是回文串,bfs转移,枚举两点出边,如果两个新端点颜色相同就更新 ...
- luogu P2572 [SCOI2010]序列操作
传送门 这个题我写了差不多一周吧-- 终于改成了一个能在考试的时候写完的版本 大量的区间操作 1e5 显然线段树解决 确实是板子题 但是极其难调-- 最后听rabbithu学姐讲了一下才用" ...
- luogu P5286 [HNOI2019]鱼
传送门 这题真的牛皮,还好考场没去刚( 这题口胡起来真的简单 首先枚举D点,然后对其他所有点按极角排序,同时记录到D的距离.然后按照极角序枚举A,那么鱼尾的两个点的极角范围就是A关于D对称的那个向量, ...
- Luogu P2572 [SCOI2010]序列操作 线段树。。
咕咕了...于是借鉴了小粉兔的做法ORZ... 其实就是维护最大子段和的线段树,但上面又多了一些操作....QWQ 维护8个信息:1/0的个数(sum),左/右边起1/0的最长长度(ls,rs),整段 ...
- 学习手记(2021/3/19~?)
上一篇有点多就开新的了 文章目录 树哈希 wqswqswqs二分 单位根反演 威佐夫博弈 范德蒙德行列式 BEST定理 平面图欧拉定理 FWT转移矩阵的推导 保序回归 一些数学小结论 范德蒙德卷积 乘 ...
- 每周记录(4月底停更了qvq)
1月6日 旋转卡壳 闵可夫斯基和 1月13日 期末复习 1月20日 网络流前4道题 一场失败的期末考试 写寒假作业 bzoj [HNOI2008]明明的烦恼(90分) prufer序列 正睿 画画图 ...
- [总结]2019年9月 OI学习/刷题记录
从现在开始记录一下每天的学习情况.主力LOJ? 2019/9/5 LibreOJ #2543. 「JXOI2018」排序问题 答案显然是\(\frac{(n+m)!}{Cnt_1!Cnt_2!\cdo ...
- 【线段树】[LUOGU 守墓人] [LUOGU 维护序列] 线段树模板题
题目: 题目链接:[LUOGU 守墓人] 题解: 线段树单点修改,区间修改,单点查询,区间查询,一系列线段树基本操作,模板打就好. (回头再补一个分块和树状数组的这种板子题,就是用分块和树状数组再写一 ...
最新文章
- linux 使用sendmail发送邮件
- 9.使用原生js实现类似于jquery的动画
- 2021京山一中高考成绩查询,京山一中的2020高考喜报三天前就发布了,钟祥一中为什么还没有公布?...
- leetcode 494. 目标和
- volatile关键字解析
- Cookie知识点总结
- 跟着开源项目学因果推断——causalnex(十三)
- Oracle 12c中导入Oracle 11g的数据
- activitygroup
- 三菱服务器显示b01,MR-JE-B三菱伺服驱动器的启动事项
- vue3.0中使用echarts
- Nodejs 中文分词
- oracle价格的数据类型,oracle数据库中的number类型
- 渲梦工厂V2.1.5.0简体中文官方版,作图快10倍~
- win7锁定计算机自动关机,手把手教你win7自动关机怎么设置
- Spice语法及调用
- 乐视商城官方微博壕送5000张电影票:生态可以这样纵横
- DecimalFormat format 方法
- 无限制分类 PHP
- 【重要】2022年国际高性能大数据暨智能系统会议征稿了!
热门文章
- 三角函数到傅立叶级数
- PumpkinRaising靶机渗透
- Sample larger than population or is negative
- 制作拨号服务器,如何打造全自动的拨号上网服务器
- 计算机教育经历个人简历,个人简历教育经历
- 源码编译Redis Desktop Manager参考
- 计算机开机界面用户如何删除,怎么删除电脑登陆账户_怎么删除电脑开机账户...
- 【Vulnhub靶场】NOOB: 1
- 九种电脑变慢的常见症状、原因、以及解决办法。
- 计算机卡慢解决方法,电脑慢的快速解决办法 四种方法电脑速度变快10倍