【洛谷P5156】【USACO18DEC】—Sort It Out(Lis计数dp+贪心)

传送门

可以发现对于一个集合内的数无论怎么操作
都只会改变这些数的相对位置,而补集没有一点变化

所以我们要求所有非集合的数必须是单调递增的(否则无论怎么操作都不能满足有序)

则集合内的数要单调递减

则我们要求的是字典序第kk小的最长下降子序列

对偶转换就变成了求字典序第kk大的最长上升子序列

我们考虑倒序处理,对于每一个长度,维护一下哪些开头的lislis长度为ii,有多少个(最长上升子序列计数做法点这儿

然后每次贪心取一下就是了

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
	return res;
}
const int N=100005;
int n,k,a[N],b[N],c[N],vis[N];
const int inf=1e18;
struct zxyakioi{
	int maxn,cnt;
	inline friend void operator +=(zxyakioi &a,zxyakioi &b){
		if(a.maxn<b.maxn)a.maxn=b.maxn,a.cnt=b.cnt;
		else if(a.maxn==b.maxn)a.cnt=min(inf,a.cnt+b.cnt);
	}
}bit[N];
inline int lowbit(int x){
	return (x&(-x));
}
inline void update(int pos,zxyakioi x){
	for(;pos;pos-=lowbit(pos)){
		bit[pos]+=x;
	}
}
inline zxyakioi query(int pos){
	zxyakioi res=(zxyakioi){0,1};
	for(;pos<=n;pos+=lowbit(pos))
	res+=bit[pos];
	return res;
}
vector<int> vec[N];
signed main(){
	n=read();
	k=read();
	for(int i=1;i<=n;i++)a[i]=read(),b[a[i]]=i;
	for(int i=n;i;i--){
		zxyakioi now=query(b[i]+1);
		now.maxn++,vec[now.maxn].push_back(i);
		c[i]=now.cnt;update(b[i],now);
	}
	int m=query(1).maxn;
	int now=-1;
	for(int i=m;i;i--){
		for(int j=0;j<vec[i].size();j++){
			int p=vec[i][j];
			if(b[p]<now)continue;
			if(k<=c[p]){
				vis[p]=1;
				now=b[p];break;
			}
			else {
				k-=c[p];
			}
		}
	}
	cout<<(n-m)<<'
';
	for(int i=1;i<=n;i++){
		if(!vis[i])cout<<i<<'
';
	}
}
原文地址:https://www.cnblogs.com/stargazer-cyk/p/10366319.html