Description
Solution
首先了,除才逆元的情况下显然是可以合并的,
所以,当一个区间的
mex
值没有变化时,就可以吧mex值相同的
r−l+1
一起结算,
设
nxi
表示下一个与
ai
相同的数的位置,
mxi
表示
mex(l,i)
,l为枚举的左端点,
我们先枚举一个l为左端点,
那么现在,我需要吧l往右移一位,那么会对
l
~
有因为从l开始的mex一定是不下降的,
那么当第一个i满足
mxi>=al
,并且
i<=nxl−1
,那么
mxi
~
mxnxl−1
都要变成
al
,
在此之前,我们先要结算这个区间的贡献,
在i~
nxl−1
这个区间中,我们先找到一个区间使得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;
}