1. 程式人生 > >luogu P5294 [HNOI2019]序列

luogu P5294 [HNOI2019]序列

get char del 單調遞增 problem d+ set lse std

傳送門

這個什麽鬼證明直接看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 double

using 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;
}

luogu P5294 [HNOI2019]序列