【NOIP模拟】Work

                                                  Work

题目描述

假设现在离 noip 还有 m 天,有 n 个人要去参加比赛。他们每个人都有一个预定的训练量 r[i] ,所以每一天他们都抓紧时间练习。但是由于条件限制,第 i 天只有 t[i] 的时间可以练习。

我们都知道,一个人在开始干活以前总要浪费一些时间做一些杂七杂八的事情。现在我们假定第 i 个人每天在训练前浪费的时间是固定的,记为 d[i] 。这段浪费掉的时间过后,选手会专心致志训练,他们会充分利用剩下的时间。然而一个可能的情况时,一个人还在无所事事的时候,某一天的训练时间已经过去了,所以他那一天什么事情都没有做。

现在请问每个人在第几天的时候可以完成自己的训练任务。当然会存在志向远大但是很懒惰的人到最后也是做不完的情况。

输入格式

第一行两个整数 n,m ,表示人数和天数 。
接下来一行 m 个整数 t[i] 。
接下来 n 行每行两个整数 d[i],r[i] 。

输出格式

一行输出 n 个整数表示每个人在第几天可以完成自己的工作,如果完不成,输出 0 。

样例数据 1

输入  [复制]

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

【注意事项】
如果某人浪费的时间超过一天,不需减去负的时间。

解析:

        对于30%的数据直接O(N ^ 2)暴力就行了。

        对于100%的数据,如果二分每个人的所需天数,则时间复杂度为O(N (log M) ^2)(吧)。虽然能过,但是我们要追求更优越的复杂度,于是就可以用线段树了。把 t ,d 数组按从大到小排序,然后从大到小计算第 i 个人的所需天数,方法就是把比 d[i] 大的 t[j] 加入线段树中,再查询就行了。时间复杂度 O(N ^ log N)

代码:
 

#include <bits/stdc++.h>
using namespace std;

const int Max=200010;
int n,m,s;
int ans[Max];
struct in{int d,r,pos;};
in num[Max];
struct ou{int pos,t;};
ou t[Max];
struct shu{int sum,num;};
shu tree[Max<<2];

inline int get_int()
{
	int x=0,f=1;
	char c;
	for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
	if(c=='-') {f=-1;c=getchar();}
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	return x*f;
}

inline bool comp1(const ou &a,const ou &b)
{
    return a.t > b.t;
}

inline bool comp2(const in &a,const in &b)
{
    return a.d > b.d;
}

inline void Insert(int root,int l,int r,int pos,int k)
{
	if(l==r)
	{
	  tree[root].sum = k,tree[root].num = 1;
	  return;
	}
	int mid = l + r >> 1;
	if(pos <= mid) Insert(root<<1 , l , mid , pos , k);
	else Insert(root<<1|1 , mid+1 , r , pos , k);
	tree[root].sum = tree[root<<1].sum + tree[root<<1|1].sum;
	tree[root].num = tree[root<<1].num + tree[root<<1|1].num;
}

inline int Q(int root,int l,int r,int k)
{
    if(l==r) return l;
    int mid = l + r >> 1;
    if(s <= tree[root<<1].sum - tree[root<<1].num * k) Q(root<<1,l,mid,k);
    else s-=tree[root<<1].sum - tree[root<<1].num * k,Q(root<<1|1,mid+1,r,k);
}

int main()
{
	n=get_int();
	m=get_int();
	for(int i=1;i<=m;i++) t[i].pos=i,t[i].t=get_int();
	for(int i=1;i<=n;i++) num[i].pos=i,num[i].d=get_int(),num[i].r=get_int();
	sort(t+1,t+m+1,comp1);
	sort(num+1,num+n+1,comp2);

    register int l=1;
	for(register int i=1;i<=n;i++)
	{
	  for(;l <= m && num[i].d <= t[l].t;l++) Insert(1,1,m,t[l].pos,t[l].t);
	  if(tree[1].sum - tree[1].num * num[i].d < num[i].r) continue;
	  s=num[i].r;
	  int pos = Q(1,1,m,num[i].d);
	  ans[num[i].pos] = pos;
	}

	for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
	return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_38083668/article/details/81173934
今日推荐