ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[Codeforces_gym_102136] I.Permutations again

2022-08-16 22:03:20  阅读:125  来源: 互联网

标签:posl int 102136 gym Permutations mid long ID define


传送门

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有