• AtCoder ARC115 E


    题目链接

    E - LEQ and NEQ

    题目大意

    给了一个序列 (A_1,A_2,...,A_N),求出满足 (1leq X_ileq A_i) 且相邻元素不同的序列 (X) 的数量,答案模 (998244353)

    (2leq Nleq 5 imes 10^5)(1leq A_ileq 10^9)

    思路

    考虑容斥,设 (f_i) 为前 (i) 位的答案,有转移式:

    [f_i=sum_{j=0}^{i-1}f_jcdot min_{j<kleq i}{A_k}cdot (-1)^{i-j-1} ]

    注意到每次多一个 (A_i) 是会改变一个区间的转移系数的,把 ((-1)^i) 扔出来后,用线段树维护所有地方的权值和(就是求和式的值),用栈记录 (A_i) 影响了哪些位置的权值,每次把当前的 (A_i) 插入进去,更新线段树即可。

    时间复杂度 (O(Nlog_2N))

    Code

    #include<iostream>
    #include<stack>
    #include<cstdio>
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define per(i,b,a) for(int i=(b);i>=(a);i--)
    #define N 500500
    #define M 2000021
    #define mod 998244353
    #define ll long long
    using namespace std;
    int a[N],n;
    struct SegmentTree{
        ll w,val,lazy;
    }t[M];
    stack<int> mn;
    ll dp[N];
    void pushdown(int x){
        if(t[x].lazy){
            t[x*2].w=(t[x*2].val*t[x].lazy)%mod;
            t[x*2+1].w=(t[x*2+1].val*t[x].lazy)%mod;
            t[x*2].lazy=t[x].lazy,t[x*2+1].lazy=t[x].lazy;
        }
    }
    void update(int x,int l,int r,int a,int b,ll k){
        if(l>=a&&r<=b){
            t[x].lazy=k,t[x].w=(t[x].val*k)%mod;
            return;
        }
        int mid=(l+r)>>1;
        if(mid>=a)update(x*2,l,mid,a,b,k);
        if(mid<b)update(x*2+1,mid+1,r,a,b,k);
        t[x].w=(t[x*2].w+t[x*2+1].w)%mod;
        t[x].val=(t[x*2].val+t[x*2+1].val)%mod;
    }
    void insert(int x,int l,int r,int loc,ll k){
        if(l==r){
            t[x].val=k,t[x].w=(t[x].val*t[x].lazy)%mod;
            return;
        }
        pushdown(x);
        int mid=(l+r)>>1;
        if(mid>=loc)insert(x*2,l,mid,loc,k);
        else insert(x*2+1,mid+1,r,loc,k);
        t[x].w=(t[x*2].w+t[x*2+1].w)%mod;
        t[x].val=(t[x*2].val+t[x*2+1].val)%mod;
    }
    int main(){
        ios::sync_with_stdio(false);
        cin>>n;
        rep(i,1,n)cin>>a[i];
        mn.push(0);
        dp[0]=1;
        insert(1,0,n,0,mod-dp[0]);
        rep(i,1,n){
            while(a[mn.top()]>a[i])mn.pop();
            update(1,0,n,mn.top(),i-1,a[i]);
            mn.push(i);
            dp[i]=(i&1)?mod-t[1].w:t[1].w;
            insert(1,0,n,i,(i&1)?dp[i]:mod-dp[i]);
        }
        cout<<dp[n]<<endl;
        return 0;
    }
    

    思路2

    然而这道题是可以做到线性的,题目这个一个点可以控制一段区间的性质,可以考虑用笛卡尔树维护,和前面一样建一个栈,不过栈中要储存 (A_i) 下标和其控制的权值和两样东西,然后直接根据奇偶性计算就可以了,时间复杂度 (O(N))

    讲起来有点玄,看代码吧。

    Code

    #include<iostream>
    #include<stack>
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define per(i,b,a) for(int i=(b);i>=(a);i--)
    #define N 500500
    #define ll long long
    #define mod 998244353
    #define fr first
    #define sc second
    using namespace std;
    int a[N],n;
    int main(){
        ios::sync_with_stdio(false);
        cin>>n;
        rep(i,1,n)cin>>a[i];
        ll val=0,sum=0;
        stack<pair<ll,int> > s;
        rep(i,1,n){
            val=sum+(i==1);
            (sum+=mod-val*a[i]%mod)%=mod;
            while(!s.empty()&&s.top().second>a[i]){
                pair<ll,int> cur=s.top();
                s.pop();
                (sum+=cur.fr*(cur.sc-a[i]))%=mod;
                (val+=cur.fr)%=mod;
            }
            s.push({val,a[i]});
        }
        cout<<(n%2?mod-sum:sum)<<endl;
        return 0;
    }
    
  • 相关阅读:
    Blender 3DOne
    [翻译]XNA外文博客文章精选之sixteen(中)
    实习技术员的基本功(二)
    [翻译]XNA外文博客文章精选之fifteen
    实习技术员的基本功(三)
    [翻译]XNA外文博客文章精选之sixteen(下)
    实习技术员的基本功(一)
    [翻译]XNA外文博客文章精选之sixteen(上)
    思维导图
    MySQL error 1045(28000): Access denied for user ...
  • 原文地址:https://www.cnblogs.com/Neal-lee/p/14608520.html
Copyright © 2020-2023  润新知