正题
题目链接:http://noi.ac/contest/266/problem/795
题目大意
nnn个人第iii个巡逻一次aia_iai秒,休息至少bib_ibi秒。
要求
- 任意时刻都有人巡逻
- 在一个人的两次相邻的巡逻直接不能有另一个人巡逻两次。
解题思路
对于性质二我们发现就是在nnn个人里选择最少的人轮流巡逻使得任意时刻都有人巡逻。
我们考虑贪心,将人按照bib_ibi排序,然后枚举就好了,这样我们就确定了最大的bib_ibi,所以我们要求前面的最大的数的和使得它的和足够就好了。
但是这样我们会发现有许多问题,因为这个人两次巡逻的间隔是不计算自己的巡逻时间的,
也就是sum−ai>bi⇒sum>bi+aisum-a_i>b_i\Rightarrow sum>b_i+a_isum−ai>bi⇒sum>bi+ai
所以我们改为按照bi+aib_i+a_ibi+ai排序就好了,然后对顶堆维护前若干个最大值使得他们的和满足max{bi+ai}max\{b_i+a_i\}max{bi+ai}
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
using namespace std;
const ll N=5e5+10;
struct node{ll t,b;
}a[N];
ll n,sum,z,ans=2147483647;
priority_queue<ll> q1,q2;
bool cmp(node x,node y)
{return x.b==y.b?x.t<y.t:x.b<y.b;}
int main()
{//freopen("data.in","r",stdin);scanf("%lld",&n);for(ll i=1;i<=n;i++){scanf("%lld%lld",&a[i].t,&a[i].b);a[i].b+=a[i].t;}sort(a+1,a+1+n,cmp);for(ll i=1;i<=n;i++){if(q1.empty()||a[i].t>-q1.top()){q1.push(-a[i].t);sum+=a[i].t;z++;}else q2.push(a[i].t);while(!q1.empty()&&sum>=a[i].b){sum+=q1.top();z--;q2.push(-q1.top());q1.pop();}while(!q2.empty()&&sum<a[i].b){sum+=q2.top();z++;q1.push(-q2.top());q2.pop();}if(sum>=a[i].b){ans=min(ans,z);}}if(ans==2147483647) printf("-1");else printf("%lld",ans);
}