【洛谷P5156】【USACO18DEC】—Sort It Out(Lis计数dp+贪心)
可以发现对于一个集合内的数无论怎么操作
都只会改变这些数的相对位置,而补集没有一点变化
所以我们要求所有非集合的数必须是单调递增的(否则无论怎么操作都不能满足有序)
则集合内的数要单调递减
则我们要求的是字典序第小的最长下降子序列
对偶转换就变成了求字典序第大的最长上升子序列
我们考虑倒序处理,对于每一个长度,维护一下哪些开头的长度为,有多少个(最长上升子序列计数做法点这儿)
然后每次贪心取一下就是了
代码:
#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)<<'\n';
for(int i=1;i<=n;i++){
if(!vis[i])cout<<i<<'\n';
}
}