题目链接:
题目大意:
有n个人,他们都会被邀请,但只有在已经接受邀请的人的数量在某个区间当中的时候,他才会选择接受邀请,问如何邀请才能保证最终接受邀请的人的数量最多。
题目分析:
- 首先初始的人数sum=0,只有当 li≤sum 的时候第i个人被邀请才有可能答应,所以我们先对所有人按照 li 从小到大排序,正好是他们加入优先队列的。然后我们每次只要从可选的人(用优先队列维护)当中选择 ri 最小的,因为如果因为人数增长导致已经在优先队列当中的人不能被选,那么一定是 ri 最小的这个,所以贪心的选择它一定会得到最优解。
- 那么如何优先队列中可以选取的元素。首先当当前的 sum≥li 那么可以将第i个人放入优先队列,表示已经可以被邀请,当 sum≥rtop 的时候,那么这个人已经不能被选了,所以应该出队,因为人已经排序,所以按顺序加入即可。
- 算法的复杂度是
O(nlog2n)
AC代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <vector>
#define MAX 100007
using namespace std;
struct Node
{
int id,l,r;
}p[MAX];
bool cmp ( Node a, Node b )
{
if ( a.l == b.l ) return a.r < b.r;
return a.l < b.l;
}
struct Node1
{
int id,r;
Node1 ( int a , int b )
{
r = a;
id = b;
}
bool operator < ( const Node1& a ) const
{
return r > a.r;
}
};
int t,n;
vector<int> ans;
priority_queue<Node1> q;
int main ( )
{
scanf ("%d" , &t );
while ( t-- )
{
scanf ( "%d" , &n );
for ( int i = 0 ; i < n ; i++ )
scanf ( "%d" , &p[i].l);
for ( int i = 0 ; i < n ; i++ )
scanf ( "%d" , &p[i].r);
for ( int i = 0 ; i < n ; i++ )
p[i].id = i+1;
sort ( p , p+n , cmp );
while (!q.empty()) q.pop();
ans.clear();
int num = 0;
int i = 0;
while ( true )
{
//cout << i << " " << p[i].l << " " << p[i].r << " " << num <<" " << q.size()<< endl;
while ( i < n && p[i].l <= num && p[i].r >= num )
{
q.push ( Node1 ( p[i].r , p[i].id ));
i++;
}
if ( !q.empty() )
{
while ( !q.empty() && q.top().r < num )
{
ans.push_back ( q.top().id );
q.pop();
}
if ( !q.empty() )
{
ans.push_back ( q.top().id );
q.pop();
num++;
}
}
if ( q.empty() && ( i >= n || p[i].l > num || p[i].r < num ) ) break;
}
for ( ;i < n ;i++ )
ans.push_back ( p[i].id );
printf ( "%d\n" , num );
for ( int i = 0 ; i < ans.size() ; i++ )
{
if ( i ) printf ( " ");
printf ( "%d" , ans[i] );
}
puts ( "");
}
}