题目描述:
假设现在离 noip 还有 m 天,有 n 个人要去参加比赛。他们每个人都有一个预定的训练量 r[i] ,所以每一天他们都抓紧时间练习。但是由于条件限制,第 i 天只有 t[i] 的时间可以练习。
我们都知道,一个人在开始干活以前总要浪费一些时间做一些杂七杂八的事情。现在我们假定第 i 个人每天在训练前浪费的时间是固定的,记为 d[i] 。这段浪费掉的时间过后,选手会专心致志训练,他们会充分利用剩下的时间。然而一个可能的情况时,一个人还在无所事事的时候,某一天的训练时间已经过去了,所以他那一天什么事情都没有做。
现在请问每个人在第几天的时候可以完成自己的训练任务。当然会存在志向远大但是很懒惰的人到最后也是做不完的情况。
输入格式:
第一行两个整数 n,m ,表示人数和天数 。
接下来一行 m 个整数 t[i] 。
接下来 n 行每行两个整数 d[i],r[i] 。
输出格式:
一行输出 n 个整数表示每个人在第几天可以完成自己的工作,如果完不成,输出 0 。
样例数据 :
输入
3 3
4 2 5
1 3
2 5
3 4输出
1 3 0
备注:
数据范围:
对 30% 的输入数据 :1≤n,m≤1000
对 100% 的输入数据 :1≤n,m≤ 200000;1≤t[i]≤1000000; 0≤d[i]≤1000000;1≤r[i]≤1000000
注意事项:
如果某人浪费的时间超过一天,不需减去负的时间。
首先,对于每个人,如果他恰好在第 i 天完成任务,那么他肯定能在 j (j > i)天内完成任务,在 k(k < i)天完不成任务
这样的话,答案具有单调性,我们可以用二分答案,现在的问题是怎么去判断 mid 是否合法
考虑用线段树,我们先对天数按从大到小排序,在对每个人按每天浪费的时间从大到小排序(排序是为了方便)
我们每次只把比第 d[ i ] 大的天数加入线段树,这样判断 mid 就用总的 t 减去总的 d 就是能完成的任务量,再与 r 比较
但是这样的话复杂度是O(n * log n * log n),还是会超时,还要再优化
由于线段树本身就有“二分”的思想,我们可以不用二分,就降了一个 log
emmm……还有不知道为何 cout 要比 printf 快,有大佬路过可以解释一下吗
#include
#include
#include
#include
#define N 200005
using namespace std;
int ans[N],sum[4*N],cnt[4*N];
struct Day
{
int t,pos;
}day[N];
struct Man
{
int d,r,pos;
}man[N];
bool comp1(const Day &p,const Day &q)
{
return p.t>q.t;
}
bool comp2(const Man &p,const Man &q)
{
return p.d>q.d;
}
void Add(int k,int l,int r,int x,int v)
{
if(l==r)
{
sum[k]=v;
cnt[k]++;
return;
}
int mid=l+r>>1;
if(x<=mid) Add(k<<1,l,mid,x,v);
else Add(k<<1|1,mid+1,r,x,v);
sum[k]=sum[k<<1]+sum[k<<1|1];
cnt[k]=cnt[k<<1]+cnt[k<<1|1];
}
int Sum(int k,int l,int r,int v,int d,int pre)
{
if(l==r) return l;
int mid=l+r>>1,ans;
if(sum[k<<1]-cnt[k<<1]*d+pre>=v) ans=Sum(k<<1,l,mid,v,d,pre);
else ans=Sum(k<<1|1,mid+1,r,v,d,pre+sum[k<<1]-cnt[k<<1]*d);
return ans;
}
int main()
{
// freopen("work.in","r",stdin);
// freopen("work.out","w",stdout);
int n,m,i,j;
scanf("%d%d",&n,&m);
for(i=1;i<=m;++i)
{
scanf("%d",&day[i].t);
day[i].pos=i;
}
sort(day+1,day+m+1,comp1);
for(i=1;i<=n;++i)
{
scanf("%d%d",&man[i].d,&man[i].r);
man[i].pos=i;
}
sort(man+1,man+n+1,comp2);
j=1;
for(i=1;i<=n;++i)
{
while(day[j].t>man[i].d&&j<=m)
{
Add(1,1,m,day[j].pos,day[j].t);
j++;
}
if(sum[1]-cnt[1]*man[i].d