原题传送门

题意:给你一个长度为\(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);
else
modify(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);
else
return 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;
else
l=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;
}

【题解】Luogu P5294 [HNOI2019]序列的更多相关文章

  1. luogu P5294 [HNOI2019]序列

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

  2. [luogu P3648] [APIO2014]序列分割

    [luogu P3648] [APIO2014]序列分割 题目描述 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了得到k+1个子序 ...

  3. [题解] Luogu P5446 [THUPC2018]绿绿和串串

    [题解] Luogu P5446 [THUPC2018]绿绿和串串 ·题目大意 定义一个翻转操作\(f(S_n)\),表示对于一个字符串\(S_n\), 有\(f(S)= \{S_1,S_2,..., ...

  4. 【题解】Luogu P2572 [SCOI2010]序列操作

    原题传送门:P2572 [SCOI2010]序列操作 这题好弱智啊 裸的珂朵莉树 前置芝士:珂朵莉树 窝博客里对珂朵莉树的介绍 没什么好说的自己看看吧 操作1:把区间内所有数推平成0,珂朵莉树基本操作 ...

  5. 【题解】Luogu P5470 [NOI2019]序列

    原题传送门 同步赛上我一开始想了个看似正确却漏洞百出的贪心:按\(a_i+b_i\)的和从大向小贪心 随便想想发现是假的,然后就写了个28pts的暴力dp 杜神后半程说这题就是个贪心,但我没时间写了 ...

  6. 题解 [HNOI2019]序列

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

  7. 【题解】Luogu P5288 [HNOI2019]多边形

    原题传送门 HN的题目就是毒瘤 我们有以下猜想: 1.最后所有的线都连到了n号点上 2.最小步数应该为n-3-已经连到n号点的线段数量 本来有些边\((a_i,n)\)会将整个图分割成很多个区间.对于 ...

  8. 洛谷 题解 UVA1626 【括号序列 Brackets sequence】

    看还没有人发记搜的题解,赶紧来水发一篇 我们定义dp[i][j]为区间i~j内最少添加几个括号才能把这个串变成正规括号序列. 考虑四种情况 i>j不存在这种子串,返回0 i==j子串长度为1无论 ...

  9. 题解 最长上升序列2 — LIS2

    最长上升序列2 - LIS2 Description 已知一个 1 ∼ N 的排列的最长上升子序列长度为 K ,求合法的排列个数. Input 输入一行二个整数 N , K ( K ≤ N ≤ 15) ...

随机推荐

  1. python 判断操作系统以及操作系统版本号

    >>> import platform >>> platform.platform() 'Darwin-17.7.0-x86_64-i386-64bit' > ...

  2. c语言用指针定义一个类型进行输入输出

    1 整型数组 // #include "stdafx.h" #include "stdlib.h" int _tmain(int argc, _TCHAR* a ...

  3. Salt-Formulas的使用

    Saltstack自0.17.x版本开始引进Formulas的概念,旨在通过简化State和集成数据来实现State的友好管理.根据SALT FORMULAS的官方文档,在完成手动添加formula目 ...

  4. Cross-channel Communication Networks

    Cross-channel Communication Networks 2019-12-13 14:17:18 Paper: https://papers.nips.cc/paper/8411-cr ...

  5. ThinkPHP 5.1 跨域中间件

    <?php namespace app\http\middleware; class CrossDomain { public function handle($request, \Closur ...

  6. java.lang.ClassNotFoundException: com.*.*.entity.time.Q*

    @Entity 实体类 java.lang.ClassNotFoundException: com.*.*.entity.time.Q* 添加依赖 1.添加DSL依赖 <!--query dsl ...

  7. Classic BAdi and New BAdi

    Former Member Classic BAdi and New BAdi ... 2007年04月27日 04:43 | 1.5k Views Hi all, I have a question ...

  8. iOS 基于 itemServices 进行本地安装 ipa 应用安装包

    itemServices 协议 itemServices 是苹果推出的一款协议.基于这款协议,我们在本地部署一个服务器,将 ipa 包存放到本地服务器.然后,测试人员只要通过 iOS 测试设备的 Sa ...

  9. LeetCode_459. Repeated Substring Pattern

    459. Repeated Substring Pattern Easy Given a non-empty string check if it can be constructed by taki ...

  10. 使用pprof调试go程序

    使用pprof调试go程序 pprof可以用来调试go程序,在go中有两个库可以使用,1. net/http/pprof 2. runtime/pprof 方法1 - net/http/pprof 测 ...