来自FallDream的博客,未经允许,请勿转载,谢谢。
考虑直接对每个数字,统计它会产生的贡献。
单调栈求出每个数字左边第一个大等于他的数,右边第一个大于他的 (注意只能有一边取等)
假设左右两边分别有x1,x2个数,较大的是mx,较小的是mn
对于长度在(mx+1,mn+mx+1]的x,会产生mn+mx+1 - x - 1的贡献
对于长度在(mn,mx+1]的数,会产生 mn+1的贡献
对于长度在[1,mn]中的数x,会产生x的贡献。
差分维护即可
#include<iostream> #include<cstdio> #define MN 1000000 #define mod 998244353 using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,a[MN+5],s[MN+5],g[MN+5],top=0,q[MN+5],Lt[MN+5],Rt[MN+5],ans=0; inline void R(int&x,int y){x+=y;x>=mod?x-=mod:0;} int main() { n=read(); for(int i=1;i<=n;++i) a[i]=read(); for(int i=1;i<=n;++i) { while(top&&a[i]>=a[q[top]]) --top; Lt[i]=q[top]+1;q[++top]=i; } q[top=0]=n+1; for(int i=n;i;--i) { while(top&&a[i]>a[q[top]]) --top; Rt[i]=q[top]-1;q[++top]=i; } for(int i=1;i<=n;++i) { int mn=min(i-Lt[i],Rt[i]-i),y=mod-(a[i]%mod),mx=max(i-Lt[i],Rt[i]-i),z=a[i]%mod; if(mn>0) R(s[1],z),R(s[mn+1],y); R(g[mn+1],1LL*(mn+1)*z%mod),R(g[mx+2],1LL*(mod-mn-1)*z%mod); R(g[mx+2],1LL*(mn+mx+2)*z%mod);R(s[mx+2],y); R(g[mn+mx+2],1LL*(mod-mn-mx-2)*a[i]%mod);R(s[mn+mx+2],z); } for(int i=1;i<=n;++i) { R(g[i],g[i-1]);R(s[i],s[i-1]); ans^=(1LL*s[i]*i+g[i])%mod; } printf("%d ",ans); return 0; }