正着想很难,但是反着想就容易有思路
/* 将问题转化为 挑选最多的线段,每个点的覆盖次数不超过k次 multiset里存k个右端点,表示第i层当前的最远右端点,每次来一根新线段,能填就填进并更新,不能填就更新右端点, 线段seg 能填进当且仅当multiset的首元素<seg.s, 然后把这个首元素删除,更新为seg.t 反之找到multiset的尾元素,如果>seg.t,那么更新为seg.t */ #include<bits/stdc++.h> #include<set> using namespace std; #define N 200005 struct Seg{int l,r,id;}seg[N]; int cmp(Seg a,Seg b){return a.l<b.l;} multiset<pair<int,int> >s; multiset<pair<int,int> >::iterator it,itt; int n,k,has[N]; int main(){ cin>>n>>k; for(int i=1;i<=n;i++){ cin>>seg[i].l>>seg[i].r; seg[i].id=i; } sort(seg+1,seg+1+n,cmp); for(int i=1;i<=k;i++)s.insert(make_pair(0,0)); int ans=0; for(int i=1;i<=n;i++){ it=s.begin(); pair<int,int> tmp=*it; if(tmp.first<seg[i].l){//能填进去 tmp.first=seg[i].r; tmp.second=seg[i].id; has[seg[i].id]=1; s.insert(tmp); s.erase(it); ans++; } else {//不能填进去 itt=s.end(); itt--; tmp=*itt; if(tmp.first>seg[i].r){ tmp.first=seg[i].r; has[tmp.second]=0; has[seg[i].id]=1; tmp.second=seg[i].id; s.insert(tmp); s.erase(itt); } } } cout<<n-ans<<' '; for(int i=1;i<=n;i++) if(!has[i])cout<<i<<" "; } /* 9 11 7 8 7 8 9 11 */