【xsy2274】 平均值 线段树
题目大意:给你一个长度为n的序列a,请你求:
n∑l=1n∑r=lmex(al,al+1,...,ar)r−l+1
对998244353取模
数据范围:n≤5×105
我们考虑把原先的式子转化一下
令s[i]=i∑j=11i。
令f[i][l]表示最小的x,满足mex(al,al+1,...,ax)≥i。若找不到这样的x,f[i][l]=n+1
不难发现,原先答案的式子我们可以转化:
lim∑i=1n∑l=1s[n−l+1]−s[f[i][l]−l]
其中lim表示最大的数x,满足0到x-1中的数都出现过
然后我们发现,当i不变时,f[i]的值是递增的,且有大量的值是相同的,且以区间的形式出现。
我们可以基于这个性质,通过线段树打标记,快速地将f[i]的值更新至f[i+1]。
线段树统计的同时维护答案的式子,每次累加即可。
1 #include<bits/stdc++.h> 2 #define M (1<<19) 3 #define L long long 4 #define mid ((a[x].l+a[x].r)>>1) 5 #define MOD 998244353 6 using namespace std; 7 8 L pow_mod(L x,L k){L ans=1;for(;k;k>>=1,x=x*x%MOD) if(k&1) ans=ans*x%MOD; return ans;} 9 L inv[M]={0},s[M]={0},n; 10 L S(int l,int r){return (s[r]-s[max(l-1,0)]+MOD)%MOD;} 11 12 struct seg{int l,r,tag,minn,maxn;L sum;}a[M*2]; 13 14 void pushup(int x){ 15 a[x].minn=min(a[x<<1].minn,a[x<<1|1].minn); 16 a[x].maxn=max(a[x<<1].maxn,a[x<<1|1].maxn); 17 a[x].sum=(a[x<<1].sum+a[x<<1|1].sum); 18 } 19 void upd(int x,int k){ 20 a[x].tag=a[x].minn=a[x].maxn=k; 21 a[x].sum=S(k-a[x].r,k-a[x].l); 22 } 23 void pushdown(int x){ 24 if(a[x].tag) upd(x<<1,a[x].tag),upd(x<<1|1,a[x].tag); 25 a[x].tag=0; 26 } 27 28 int build(int x,int l,int r){ 29 a[x].l=l; a[x].r=r; if(l==r) return a[x].minn=a[x].maxn=l; 30 build(x<<1,l,mid); build(x<<1|1,mid+1,r); pushup(x); 31 } 32 33 void updata(int x,int l,int r,int k){ 34 if(a[x].minn>=k) return; 35 if(a[x].l==a[x].r){ 36 a[x].minn=a[x].maxn=max(a[x].maxn,k); 37 a[x].sum=S(k-a[x].l,k-a[x].l); 38 return; 39 } 40 if(l<=a[x].l&&a[x].r<=r){ 41 if(a[x].maxn<k){ 42 upd(x,k); 43 return; 44 } 45 } 46 pushdown(x); 47 if(l<=mid) updata(x<<1,l,r,k); 48 if(mid<r) updata(x<<1|1,l,r,k); 49 pushup(x); 50 } 51 52 struct node{ 53 int x,id; node(){x=id=0;} 54 friend bool operator <(node a,node b){return a.x==b.x?a.id<b.id:a.x<b.x;} 55 }p[M]; 56 57 int main(){ 58 for(int i=1;i<M;i++) inv[i]=pow_mod(i,MOD-2); 59 for(int i=1;i<M;i++) s[i]=(s[i-1]+inv[i])%MOD; 60 for(int i=1;i<M;i++) s[i]=(s[i-1]+s[i])%MOD; 61 62 scanf("%d",&n); build(1,1,n); 63 for(int i=1;i<=n;i++) scanf("%d",&p[i].x),p[i].id=i; 64 sort(p+1,p+n+1); p[0].x=-1; p[n+1].x=19890604; 65 66 L ans=0,hh=0; 67 68 for(int i=1,j=1;i<=n;hh++){ 69 if(p[i].x!=p[i-1].x+1) break; 70 while(p[i].x==p[j].x) j++; 71 72 for(int last=0;i<=j;i++){ 73 if(i==j){ 74 if(last<n) updata(1,last+1,n,n+1); 75 break; 76 } 77 updata(1,last+1,p[i].id,p[i].id); 78 last=p[i].id; 79 } 80 81 ans=(ans+a[1].sum)%MOD; 82 } 83 84 cout<<(s[n]*hh-ans+MOD)%MOD<<endl; 85 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!