【UNR #1】争夺圣杯

SOL:

   这道题长得像一个多阶差分,并且事实上这道题就是这样做的。

   我们通过跑两遍单调栈求其左边最远的比其小的和右边的最远的比其小的。

   冷静一下,发现若一个点比其左右都大的话,它在下一行的贡献会变多,只有一边大的话会不变,比两边都小的话会变小。

   对差分进行差分就好啦。

  

#include<bits/stdc++.h>
#define sight(c) ('0'<=c&&c<='9')
#define N 2000007
#define LL long long
#define inf (INT_MAX)
#define mo 998244353
//#define int LL
using namespace std;
inline void read(int &x){
    static char c;
    for (c=getchar();!sight(c);c=getchar());
    for (x=0;sight(c);c=getchar())x=x*10+c-48;
}
void write(LL x){if (x<10) {putchar('0'+x); return;} write(x/10); putchar('0'+x%10);}
inline void writeln(LL x){ if (x<0) putchar('-'),x*=-1; write(x); putchar('\n'); }
inline void writel(LL x){ if (x<0) putchar('-'),x*=-1; write(x); putchar(' '); }
struct Node{
    int id,key;
    inline bool operator <(const Node&X)const{
        return key<X.key;
    }
}qjj[N];
int sta[N],top,p[N],g[N],n,a[N];
LL ans,anw,sum,xxoo[N],dla[N];
signed main () {
    read(n);
    for (int i=1;i<=n;i++) read(a[i]),ans+=a[i];
    a[0]=inf; a[n+1]=inf;
    for (int i=1;i<=n+1;i++) {
        while (top&&a[sta[top]]<a[i]) p[sta[top--]]=i;
        sta[++top]=i; 
    } top=0;
    for (int i=n;~i;i--) {
        while (top&&a[sta[top]]<=a[i]) g[sta[top--]]=i;
        sta[++top]=i; 
    }
    dla[0]=ans;
    for (int i=1;i<=n;i++) {
        xxoo[min(p[i]-i-1,i-g[i]-1)]-=a[i]; 
        xxoo[max(p[i]-i-1,i-g[i]-1)]-=a[i];
        xxoo[p[i]-g[i]-1]+=a[i];
        
    }
    for (int i=1;i<=n;i++) dla[i]+=dla[i-1]+xxoo[i-1];
    anw=ans%mo;
    for (int i=1;i<n;i++) ans=ans+dla[i],anw^=ans%mo;
    writeln(anw); return 0;
}

猜你喜欢

转载自www.cnblogs.com/rrsb/p/8921818.html