其他分享
首页 > 其他分享> > [Codeforces_gym_102136] I.Permutations again

[Codeforces_gym_102136] I.Permutations again

作者:互联网

传送门

Description

Given a sequence \(A_i\) consisting of \(N\) integers. Find the number of pairs \((L, R)\) for which the subsegment \({A_L, A_{L + 1}, ...,A_R}\) is a permutation of \(R - L + 1\) numbers.

A permutation of \(K\) numbers is any sequence of numbers from \(1\) to \(K\), where each element occurs only once.

\(1 \le A_i\le N\), \(1\le N\le 10^6\)


Solution

给一个数列,问有多少个子串是一个从 \(1\) 开始的排列。

从第 \(N\) 位开始倒着考虑每一位作为左端点 \(l\) 的贡献。

右端点 \(r\) 合法的充要条件如下:

  1. \({A_l,…, A_r}\) 区间最小值为 \(1\),最大值为 \(r-l+1\)。
  2. \({A_l,…, A_r}\) 中没有重复的数字。

令 \(posl\) 表示对于当前从 \(l\) 开始第一个 \(1\) 出现的位置,\(posr\) 表示从 \(l\) 开始第一个重复数字出现的前一位,则合法的右端点必然在\([posl, posr]\) 之间。

接下来只需要满足区间最大值是区间的长度即可。

我们可以实时维护 \([l, n]\) 中每一位 \(k(l\le k\le n)\) 的 \({A_l,…, A_k}\) 的区间最大值,这个最大值显然可以按照值的大小分成递增的一段一段的,然后每次新加入一个 \(A_l\) 的时候,有可能会合并最前面的几段,使得他们的值为 \(A_l\), 这个部分用一个栈可以维护。

对于每一段,最多只可能有一个点可以成为合法的右端点,也就是贡献只会是 \(1\) 和 \(0\)。

每一段 \([L,R]\) 值为 \(val\) ,它贡献为 \(1\) 的时候,当前的左端点在区间 \([L-val+1,r-val+1]\),可以记录一下贡献产生的位置和贡献消失的位置,在左端点不断左移的同时维护这个贡献和。如果一个区间被合并了,那么把它的贡献删除,考虑新的合并后的贡献。

复杂度可以做到 \(O(n)\),下面为了方便写了 \(O(n\log n)\)。


Code

#include<bits/stdc++.h>
#define ll long long
//#define int long long
#define db double
#define ld long double
#define dbg1(x) cerr<<#x<<"="<<(x)<<" "
#define dbg2(x) cerr<<#x<<"="<<(x)<<"\n"
#define dbg3(x) cerr<<#x<<"\n"
using namespace std;
#define reg register
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define Debug debug("Passing [%s] in LINE %d\n",__FUNCTION__,__LINE__)
#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3f
typedef pair<int,int> pii;
#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;++i)
#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;--i)
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define FOr(i,a,b) for(int i=(a);i>=(b);--i)
#define y1 y11111111111
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
#define mod 998244353
inline int qpow(int x,ll y,int m=mod){int r=1;for(;y;y>>=1,x=(ll)x*x%m)if(y&1)r=(ll)r*x%m;return r;}
inline long long read()
{
    long long 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<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
const int MN = 1e6 + 5;
int n;
int a[MN], b[MN];
std::vector<std::pair<int, pii> > I;
int t[MN];
void C(int x, int y) {for(; x <= n; x += (x & -x)) t[x] += y;}
int G(int x) {int ret = 0; for(; x; x -= (x & -x)) ret += t[x]; return ret;}
int cal(int l, int r) {
    if(l > r) return 0;
    return G(r + 1) - G(l);
}
int _[MN];
void upd(int x, int y){C(x + 1, y - _[x]); _[x] = y;}
int app[MN], dis[MN];
std::vector<int> App[MN], Dis[MN];
int main() {
    n = read();
    REP(i, 1, n + 1) a[i] = read();
    int posl = n + 1, posr = n;
    long long ans = 0;
    DREP(i, n, 0) {
        if(a[i] == 1) posl = i;
        if(b[a[i]]) {
            posr = min(posr, b[a[i]] - 1);
        }
        b[a[i]] = i;
        //add interval l = i, r = ?
        int l = i, r = i, val = a[i];
        while(I.size()) {
            pair<int, pii> o = I.back();
            if(o.fi <= val) {
                r = o.se.se;
                upd(I.size() - 1, 0);
                I.pop_back();
            }
            else break;
        }
        I.pb(mkp(val, mkp(l, r)));
        int ID = I.size() - 1;
        int a_ = r - val + 1, b_ = l - val;
        app[ID] = a_;
        dis[ID] = b_;
        if(app[ID] >= i && i > dis[ID]) upd(ID, 1);
        else upd(ID, 0);
        if(app[ID] > 0 && app[ID] < i) App[app[ID]].pb(ID);
        if(dis[ID] > 0 && dis[ID] < i) Dis[dis[ID]].pb(ID);

        REP(o, 0, App[i].size()) {
            int IDD = App[i][o];
            if(app[IDD] == i) upd(IDD, 1);
        }
        REP(o, 0, Dis[i].size()) {
            int IDD = Dis[i][o];
            if(dis[IDD] == i) upd(IDD, 0);
        }
        App[i].clear();
        Dis[i].clear();

        if(posl <= posr) {
            //posl
            int id_l;
            l = 0, r = I.size() - 1;
            while(l <= r) {
                int mid = (l + r) >> 1;
                if(I[mid].se.fi <= posl && I[mid].se.se >= posl) {id_l = mid; break;}
                else if(posl > I[mid].se.se) r = mid - 1;
                else l = mid + 1;
            }
            //posr
            int id_r;l = 0; r= I.size() - 1;
            while(l <= r) {
                int mid = (l + r) >> 1;
                if(I[mid].se.fi <= posr && I[mid].se.se >= posr) {id_r = mid; break;}
                else if(posr > I[mid].se.se) r = mid - 1;
                else l = mid + 1;
            }
            int res = cal(id_r + 1, id_l - 1);
            //cal id_l
            int VAL = I[id_l].fi;
            int ned = i + VAL - 1;
            if(ned >= posl && ned <= posr && ned >= I[id_l].se.fi && ned <= I[id_l].se.se) ++res;
            //cal id_r
            VAL = I[id_r].fi;
            ned = i + VAL - 1;
            if(id_l != id_r && ned >= posl && ned <= posr && ned >= I[id_r].se.fi && ned <= I[id_r].se.se) ++res;
            ans += res;
        }
    }
    printf("%lld\n", ans);
    return 0;
}

标签:posl,int,102136,gym,Permutations,mid,long,ID,define
来源: https://www.cnblogs.com/PaperCloud/p/20220814I.html