p5156 [USACO18DEC]Sort It Out

传送门

分析

我们发现对于没有发现的点相对位置不会发生改变

于是我们可以吧问题转化为求一个lis

于是我们字典序第k小的答案就是字典序第k大的lis

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
#define int long long
const int inf = 1e18;
int a[100100],pl[100100],sum[100100],n,m;
vector<int>v[100100];
bool is[100100];
struct node {
    int ans,tot;
};
node d[100100];
inline void add(node &x,node y){
    if(x.ans<y.ans)x.ans=y.ans,x.tot=y.tot;
      else if(x.ans==y.ans)x.tot=min(inf,x.tot+y.tot);
}
inline int lb(int x){return x&(-x);}
inline node q(int x){node res={0,1ll};while(x<=n)add(res,d[x]),x+=lb(x);return res;}
inline void add(int x,node k){while(x)add(d[x],k),x-=lb(x);}
signed main(){
    int i,j,k;
    scanf("%lld%lld",&n,&k);
    for(i=1;i<=n;i++)scanf("%lld",&a[i]),pl[a[i]]=i;
    for(i=n;i>0;i--){
      node res=q(pl[i]+1);
      res.ans++;
      v[res.ans].push_back(i);
      sum[i]=res.tot;
      add(pl[i],res);
    }
    m=q(1).ans;
    int P=-1;
    for(i=m;i>0;i--)
      for(j=0;j<v[i].size();j++){
          if(pl[v[i][j]]<P)continue;
          if(sum[v[i][j]]>=k){
            is[v[i][j]]=1;
            P=pl[v[i][j]];
            break;
        }else k-=sum[v[i][j]];
      }
    printf("%lld
",n-m);
    for(i=1;i<=n;i++)
      if(!is[i])printf("%lld
",i);
    return 0;
}
原文地址:https://www.cnblogs.com/yzxverygood/p/10453666.html