- Sources:C - Goose Goose Duck
- Abstract:有 \(n\) 個人正在做游戲,其編號順次為 \(1,\dots,n\) ,當且僅當目前有 \([l_i,r_i]\) 人加入游戲時,第 \(i\) 個人會加入游戲。構造加入游戲的順序方案,使加入游戲的總人數最大。
- Keywords:貪心,構造(簽到題)
- Solution:將 \([l_i,r_i]\) 按左端點排序,順次枚舉右邊界,判斷合法的人,并將最早將不能加入(即\(r_i\)最小)的人加入即可,此處可使用堆維護。復雜度\(O(n\log n)\)。
- Code:
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define int ll
#define endl "\n"
using pii=pair<int,int>;
struct node{
int l,r,i;
};
bool cmp(node a,node b){
if(a.l!=b.l) return a.l<b.l;
return a.r<b.r;
}
bool cmp1(pii a,pii b){
if(a.first!=b.first) return a.first>b.first;
return a.second>b.second;
}
void solve(){
int n;cin>>n;
vector<node>v(n);
for(int i=0;i<n;i++){
cin>>v[i].l>>v[i].r;
v[i].i=i+1;
}
sort(v.begin(),v.end(),cmp);
int cnt=0;
priority_queue<pii,vector<pii>,bool(*)(pii,pii)>pq(cmp1);
vector<int>ans;
for(int i=0;i<n;i++){//枚舉右邊界
while(cnt<n&&v[cnt].l<=i)//先看左端點是否合法,合法的入堆
pq.push({v[cnt].r,v[cnt].i}),cnt++;
while(pq.size()&&pq.top().first<i)//再看右端點是否合法,不合法的出堆
pq.pop();
if(pq.empty())//無可行解
break;
ans.push_back(pq.top().second);//優先將右邊界最小的人加入
pq.pop();
}
cout<<ans.size()<<endl;
for(auto i:ans) cout<<i<<' ';
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0);
int t=1;
while(t--) solve();
return 0;
}