【JZOJ 4939】平均值

来源:互联网 发布:怎么去兼职做美工外包 编辑:程序博客网 时间:2024/05/14 19:47

Description

这里写图片描述

Solution

首先了,除才逆元的情况下显然是可以合并的,
所以,当一个区间的mex值没有变化时,就可以吧mex值相同的rl+1一起结算,
nxi表示下一个与ai相同的数的位置,mxi表示mex(l,i),l为枚举的左端点,
我们先枚举一个l为左端点,
那么现在,我需要吧l往右移一位,那么会对l~(nxl1)这个区间的mex产生影响,
有因为从l开始的mex一定是不下降的,
那么当第一个i满足mxi>=al,并且i<=nxl1,那么mxi~mxnxl1都要变成al
在此之前,我们先要结算这个区间的贡献,
在i~nxl1这个区间中,我们先找到一个区间使得mx值相同,又因为我们可以记录第一次mx为这个值的时间,于是就可以求出每个位置分别被乘上了怎么逆元,自己在草稿纸上写一下就可以发现这个用公式很好求,
为了完成上面的操作,可以使用线段树,

复杂度:O(nlog(n))

虽然说你每次要找到mx相同的区间,这个要很多的时间,但每次找完了以后,你每个访问的区间的mx都会变为一样的,所以复杂度是可以保证的,

Code

#include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define min(q,w) ((q)<(w)?(q):(w))#define max(q,w) ((q)>(w)?(q):(w))using namespace std;typedef long long LL;const int N=6e5,mo=998244353;int read(int &n){    char ch=' ';int q=0,w=1;    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());    if(ch=='-')w=-1,ch=getchar();    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;}int n,m;int a[N],zx[N];struct qqww{int v,n;}A[N];int z[N];LL ans;LL ny[N],nys[N],nyss[N];struct wwqq{int la,lat,ti,l,r,mx;bool sm;}b[10*N];bool PX(qqww q,qqww w){return q.v<w.v||(q.v==w.v&&q.n<w.n);}LL ksm(LL q,LL w){    q%=mo;    LL ans=1;    while(w)    {        if(w&1)ans=ans*q%mo;        q=q*q%mo;w>>=1;    }    return ans;}LL H(int l,int r,int s,int t){    l=l-s+1,r=r-s+1;    LL ans=(nyss[r]-nyss[r-(t-s+1)]+mo)%mo;    ans=(ans-nyss[l-1]+nyss[max(0,l-(t-s+1)-1)]+mo)%mo;    return ans;}void merge(wwqq &e,wwqq q,wwqq w){    e.sm=q.sm&&w.sm&&(q.mx==w.mx);    e.mx=max(q.mx,w.mx);    e.ti=q.ti;}void build(int l,int r,int e){    b[e].l=l,b[e].r=r;    b[e].ti=1;    b[e].la=-1;    if(l==r)    {        b[e].mx=b[e].mx=A[l].v;        b[e].sm=1;        return;    }    int t=(l+r)>>1;    build(l,t,e*2);build(t+1,r,e*2+1);    merge(b[e],b[e*2],b[e*2+1]);}void doit(int e,int la,int lat){    if(b[e].la!=-1)    {        b[e].mx=b[e].la,b[e].ti=b[e].lat;    }    b[e].la=la,b[e].lat=lat;    b[e].sm=1;    ans=(ans+b[e].mx*H(b[e].l,b[e].r,b[e].ti,b[e].lat))%mo;}void putdown(int l,int r,int e){    if(b[e].la==-1)return;    b[e].mx=b[e].la,b[e].ti=b[e].lat+1;    if(l!=r)    {        b[e*2].la=b[e*2+1].la=b[e].la;        b[e*2].lat=b[e*2+1].lat=b[e].lat;    }    b[e].la=-1;}void change(int l,int r,int e,int l1,int r1,int la,int lat){    int t=(l+r)>>1;    putdown(l,t,e*2),putdown(t+1,r,e*2+1);    if(b[e].mx<la)return;    if(l>=l1&&r<=r1&&b[e].sm)    {        if(b[e].mx>=la)        {            doit(e,la,lat);            putdown(l,r,e);        }        return;    }    if(r1<=t)change(l,t,e*2,l1,r1,la,lat);        else if(t<l1)change(t+1,r,1+e*2,l1,r1,la,lat);            else             {                change(l,t,e*2,l1,t,la,lat);                change(t+1,r,e*2+1,t+1,r1,la,lat);            }    merge(b[e],b[e*2],b[e*2+1]);}int main(){    freopen("average.in","r",stdin);    freopen("average.out","w",stdout);    LL q;    read(n);    fo(i,1,n)A[i].v=read(a[i]),A[i].n=i;    fo(i,1,n)    {        ny[i]=ksm(i,mo-2),        nys[i]=(ny[i]+nys[i-1])%mo;        nyss[i]=(nys[i]+nyss[i-1])%mo;        zx[i]=n+1;    }    sort(A+1,A+1+n,PX);    fo(i,1,n-1)if(A[i].v==A[i+1].v)zx[A[i].n]=A[i+1].n;    fo(j,0,n)z[j]=0;    q=0;    fo(i,1,n)    {        z[a[i]]++;        while(z[q])q++;        A[i].v=q;    }    build(1,n,1);    fo(i,1,n)    {        change(1,n,1,i,zx[i]-1,a[i],i);    }    printf("%lld\n",ans);    return 0;}
0 0
原创粉丝点击