1. 程式人生 > >2018牛客多校第五場 H.subseq

2018牛客多校第五場 H.subseq

print int space 跳出循環 date open 遞增 code play

題意:

  給出a數組的排列。求出字典序第k小的b數組的排列,滿足1<=bi<=n,bi<bi+1,a[b[i]]<a[b[i+1]],m>0。

題解:

  用樹狀數組倒著求出以每個數為首的遞增子序列個數。若總的個數之和小於k則輸出-1。

  總的個數可能非常大而k<=1e18。所以要判下上界。

  最後從1~n掃一遍。當前數大於上一個加入答案的數時,若以它為首的遞增子序列個數小於k,則用k減去那個個數,否則將這個數加入答案並將k-1(即減去後面不再加數的情況)。

  k = 0時跳出循環。

技術分享圖片
#include <bits/stdc++.h>
using
namespace std; typedef long long ll; const int N = 5e5+10; const ll inf = 1e18+10; int n, tot, pre; ll k, sum; int a[N], id[N], ans[N]; ll tre[N], val[N]; ll add(ll x, ll y) { return min(x + y, inf); } void update(int pos, ll val) { while(pos > 0) { tre[pos] = add(tre[pos], val); pos
-= pos&(-pos); } } ll query(int pos) { ll res = 0; while(pos <= n) { res = add(res, tre[pos]); pos += pos&(-pos); } return res; } int main() { scanf("%d%lld", &n, &k); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); id[i]
= a[i]; } sort(id+1, id+n+1); for(int i = n; i >= 1; i--) { int p = lower_bound(id+1, id+n+1, a[i])-id; val[i] = query(p+1)+1; update(p, val[i]); } for(int i = 1; i <= n; i++) sum = add(sum, val[i]); if(sum < k) { puts("-1"); return 0; } for(int i = 1; i <= n; i++) { if(k == 0) break; if(a[i] <= a[pre]) continue; if(val[i] < k) k -= val[i]; else { ans[++tot] = i; k--; pre = i; } } printf("%d\n", tot); for(int i = 1; i < tot; i++) printf("%d ", ans[i]); printf("%d\n", ans[tot]); }
View Code

2018牛客多校第五場 H.subseq