【UOJ UNR #1】争夺圣杯

来自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\n",ans);
    return 0;
}

 

posted @ 2017-09-01 17:47  FallDream  阅读(278)  评论(0编辑  收藏  举报