1 条题解

  • 0
    @ 2025-8-24 22:06:09

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar DDOSvoid
    **

    搬运于2025-08-24 22:06:09,当前版本为作者最后更新于2018-11-05 18:58:41,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    Solution

    subtask 1

    直接 2n2^n 枚举子集,然后判断即可,注意要把合法的最长的 IBvl 序列存下来,最后排个序即可

    subtask 3

    求字典序最小的最长上升子序列

    考虑求最长上升子序列的 O(nlog)O(nlog) 的做法

    实际上是开了一个数组,d[i]d[i] 表示长度为 i 子序列最后一位最小可以是多少,我们在记录 d 数组的同时将所有长度为 i 的子序列的最后一位所在的位置都存下来。

    最后贪心选即可

    注意要倒着求

    subtask 4

    求字典序最小/次小/第三小的最长上升子序列

    这个我除了正解不会别的做法

    乱搞AC

    subtask 2

    其实如果知道了 O(n2)O(n^2) 的做法就离正解不远了

    f[i]f[i] 表示 i 向后的 IBvl 的最长长度,g[i]g[i] 表示方案数

    显然可以 O(n2)O(n^2) 求这两个数组

    那么我们有了这两个数组之后,就可以求第 k 小了

    肯定是要逐位确定

    首先枚举 f[i]==mxf[i]==mx 的 i

    按照原下标排序,如果 g[i]<kg[i]<k,则说明这一位不能选 ii,并且将 k - g[i]。重复知道 g[i]kg[i]\ge k,说明这一位一定是 i。

    那么就可以逐步确定,具体的做法是先按照 f[i]f[i] 从大到小排序,对于 f[i]f[i] 相同的,按照原下标排序

    subtask 5

    我们发现 subtask 2 的瓶颈在于求 f 和 g 数组。

    对于 f 的转移 f[i]=maxj=i+1n(f[j]+1)(a[j]+L<a[i]<a[j]+R)f[i]=max_{j=i+1}^n(f[j]+1)(a[j]+L< a[i]<a[j]+R)

    发现可以转移的是一段区间,所以那线段树维护就好了

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    #include<cstring>
    #define gc getchar
    #define maxn 500010
    #define cs const seg
    //#define ll __int128
    #define ll long long
    #define INF 1000000000
    #define pc putchar
    using namespace std;
    
    ll read(){
        ll x = 0; bool f = 0; char c = gc();
        while(!isdigit(c)){if(c == '-') f = 1; c = gc();}
        while(isdigit(c)){x = x * 10 + c - '0'; c = gc();}
        return f ? -x : x;
    }
    
    int st[maxn], top;
    void write(ll x){
        if(!x) pc('0'); top = 0;
        while(x){st[++top] = x % 10; x /= 10;}
        while(top) putchar(st[top--] + '0'); puts("");
    }
    
    int n, L, R; ll K;
    
    int a[maxn], b[maxn * 3], c1, cnt;
    void init_hash(){ c1 = n; a[0] = INF;
        for(int i = 1; i <= n; ++i) b[i] = a[i] = read();
        for(int i = 1; i <= n; ++i) b[++c1] = a[i] + L, b[++c1] = a[i] + R;
        sort(b + 1, b + c1 + 1); cnt = unique(b + 1, b + c1 + 1) - b - 1;
    }
    
    inline int get_pos(int v){return lower_bound(b + 1, b + cnt + 1, v) - b;}
    
    inline bool check(int x, int y){
        if(x == INF) return 1;
        return y - x > L && y - x < R;
    }
    
    #define lc i << 1
    #define rc i << 1 | 1
    struct seg{
        int v, id; ll s;
        seg(int _v = 0, ll _s = 0){v = _v; s = _s;}
    }T[maxn * 12], A[maxn];
    inline void maintain(seg &o, seg ls, seg rs){
        o.v = max(ls.v, rs.v); o.s = 0;
        if(ls.v >= rs.v && ls.v) o.s += ls.s;
        if(ls.v <= rs.v && rs.v) o.s += rs.s;
        o.s = max((ll)1, o.s); o.s = min(o.s, K + 1);
    }
    
    void update(int i, int l, int r, int k, cs &o){
        if(l == r){
            if(o.v > T[i].v) T[i] = o;
            else if(o.v == T[i].v) T[i].s += o.s;
            T[i].s = min(T[i].s, K + 1);
            return ;
        } int m = l + r >> 1;
        if(k <= m) update(lc, l, m, k, o);
        else update(rc, m + 1, r, k, o);
        maintain(T[i], T[lc], T[rc]);
    }
    
    seg query(int i, int l, int r, int L, int R){
        if(l > R || r < L) return seg(0, 0);
        if(L <= l && r <= R) return T[i];
        int m = l + r >> 1;
        seg t, t1 = query(lc, l, m, L, R), t2 = query(rc, m + 1, r, L, R);
        maintain(t, t1, t2); return t;
    }
    
    inline bool cmp(cs &u, cs &v){
        if(u.v == v.v) return u.id < v.id;
        return u.v > v.v;
    }
    int ans[maxn], c2;
    int main(){
        n = read(); K = read(); L = read(); R = read();
        init_hash();
        for(int i = n; i; --i){
            A[i] = query(1, 1, cnt, get_pos(a[i] + L) + 1, get_pos(a[i] + R) - 1); 
            A[i].id = i; ++A[i].v;
            update(1, 1, cnt, get_pos(a[i]), A[i]);
        }
        //    for(int i = 1; i <= n; ++i) cerr << A[i].v << " " << A[i].s << endl;
        sort(A + 1, A + n + 1, cmp); int p = 0, la = 0;
        ll tot = 0;
        for(int i = 1; i <= n; ++i) if(A[i].v == A[1].v) tot += A[i].s;
        //write(tot);
        for(int i = 1; i <= n; i = p){
            p = i;
            while(A[p].v == A[i].v) ++p;
            for(int j = i; j < p; ++j){
                if(A[j].id < la || !check(a[la], a[A[j].id])) continue;
                if(A[j].s >= K){
                    ans[++c2] = A[j].id; la = A[j].id;
                    break;
                }
                K -= A[j].s;
            }
        }
        cout << A[1].v << endl;
        for(int i = 1; i <= c2; ++i) printf("%d ", ans[i]);
        return 0;
    }
    

    rqy 的代码

    #include <algorithm>
    #include <cctype>
    #include <cstdio>
    #include <cstring>
    typedef long long LL;
    const int S = 10000000;
    struct Read {
      inline char gc() { static char buf[S], *p = buf, *end = buf; return p == end ? feof(stdin) ? (char)EOF : (end = buf + fread(p = buf, 1, S, stdin), *(p++)) : *(p++); }
      template<typename T> Read &operator[](T &ans) { ans = 0; int c, f = 1; while (!isdigit(c = gc())) if (c == '-') f = -1; do ans = ans * 10 + c - '0'; while (isdigit(c = gc())); ans *= f; return *this; }
    } read;
    struct Write {
      char obuf[S], *op, *oend; Write() { op = obuf; oend = obuf + S; }
      inline void flush() { fwrite(obuf, 1, op - obuf, stdout); op = obuf; } inline void putChar(char c) { if (op == obuf) flush(); *(op++) = c; }
      template <typename T> Write &operator[](T ans) { static int c[20]; int p = 0; while (ans) c[p++] = ans % 10, ans /= 10; while (p--) putChar(c[p] + '0'); return *this; }
      Write &operator[](char c) { putChar(c); return *this; }
      ~Write() { flush(); }
    } write;
    const int N = 500050;
    int n, m, L, R, A[N], NL[N], NR[N], B[N], f[N], hd[N], nxt[N], len; LL K, num[N];
    void Discretize() { for (int i = 0; i < n; ++i) B[i] = A[i];
      std::sort(B, B + n); m = std::unique(B, B + n) - B;
      for (int i = 0; i < n; ++i) A[i] = std::lower_bound(B, B + m, A[i]) - B;
      for (int i = 0, j = 0; i < m; NL[i] = j, ++i) while (j < m && B[j] <= B[i] + L) ++j;
      for (int i = 0, j = 0; i < m; NR[i] = j, ++i) while (j + 1 < m && B[j + 1] < B[i] + R) ++j; }
    struct Msg { int maxv; LL numv; Msg(int x = 0, LL v = 0) : maxv(x), numv(v) {}
      inline void operator+=(const Msg &rhs) { if (maxv < rhs.maxv) maxv = rhs.maxv, numv = rhs.numv; else if (maxv == rhs.maxv) numv = std::min(K, numv + rhs.numv); }
    } msgv[1200000];
    void Modify(int x, int f, LL v) { Msg adv = Msg(f, v); for (x += len + 1; x; x >>= 1) msgv[x] += adv; }
    Msg Query(int l, int r) { Msg ans = Msg(0, 1); if (l > r) return ans;
      for (l += len, r += len + 2; l + 1 != r; l >>= 1, r >>= 1) { if (~l & 1) ans += msgv[l | 1]; if (r & 1) ans += msgv[r & ~1]; } return ans; }
    int main() { read[n][K][L][R]; for (int i = 0; i < n; ++i) read[A[i]];
      Discretize(); len = 1; while (len < m + 2) len <<= 1;
      memset(hd, -1, sizeof hd);
      for (int i = n - 1; i >= 0; --i) { Msg ans = Query(NL[A[i]], NR[A[i]]); Modify(A[i], f[i] = ans.maxv + 1, num[i] = ans.numv); nxt[i] = hd[f[i]]; hd[f[i]] = i; }
      int ans1 = 0; while (~hd[ans1 + 1]) ++ans1; write[ans1]['\n'];
      for (int i = ans1, last = -1, l = 0, r = m - 1; i; --i) for (int j = hd[i]; ~j; j = nxt[j]) if (j > last && A[j] >= l && A[j] <= r)
        if (num[j] >= K) { write[(last = j) + 1][' ']; l = NL[A[j]]; r = NR[A[j]]; break; } else K -= num[j];
    }
    
    • 1

    信息

    ID
    4012
    时间
    2000ms
    内存
    500MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者