2020.12.1考试题解

L君找工作

【问题描述】

L君是个热爱生活的好青年,暑假来临,他要为自己找份工作。
暑假共有 M 天,从1到m进行编号,在第 i 天,L君共有 ti 的时间供自己自工作,
当然,每一天L君可以选择休息不去工作。
通过好朋友P君的帮助,现在L君收集到了N份工作信息,工作从 1 到 N 编号,
根据收集来的信息,L君给每份工作确定了两个参数dj 和 rj;
若某天L君决定参与第 j 份工作,那么不论哪一天,他都会先花 dj 的时间准
备这一天的工作。
若L君要参与第 j 份工作,那么他一共要工作 的时间才能算完成这项工作。
因此,若L君在第 i 天选择参与第 j 份工作,那么他会先花dj的时间来准备,
这天剩下能用来工作的时间他就会去做这份工作,若 ti < dj 则说明这天不能参与这
份工作。
一份工作需要做至少 的时间才算完成(一天准备工作的时间不算在内),
因此一份工作可能需要多天才能完成。
L君精力有限,因此他只想在暑假选择单独一份工作参与,又由于L君想尽
早结束工作去找好友P君一起玩耍,所以他想请你求出在单独只做一份工作的情
况下每份工作最早能在第几天完成。你能帮助他吗?

【输入格式】

第一行包含两个正整数 n, m 表示工作数与天数。
第二行包含m个正整数 ti,表示每天的工作时间。
接下来n行每行包含两个非负整数 di, ri,表示这份工作每天需要的准备时间
与需要完成的工作总时间。

【输出格式】

按输入的顺序输出一行 n 个整数,表示每份工作最早在第几天可以做完。若
这份工作在这 m 天内无法完成则输出0.

【样例输入】

3 3
4 2 5
1 3
2 5
3 4

【样例输出】

1 3 0

分析:

暴力做法,直接(;O(n imes m);)扫描,可以拿(;25;)分。

可能还有其他奇奇怪怪的优化可以拿部分分,但我不会这里就不讲了。

正解:

我们对于每一个任务,要求满足(;sumlimits_{j=1}^m{(t_j-d_i)}>r_i;)的最小的(;j;)

可以发现,这是一个二维偏序,这里有两种做法。

(<1>;)我们可以用主席树,建立一个以输入顺序为序的主席树,对于每一个任务,我们可以二分区间查找前缀和,找出答案。

(<2>;)我们考虑去掉一维,采用离线。

我们将天数按时间从大到小排序,任务也按准备时间从大到小排序,这样一来,我们每次将大于当前任务的(;d_i;)的天加入序列。很容易得知,我们每天都只会入列一次,减少了很多重复的扫描,且之前的可以被后面的继承。

(Code):

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7,M=2e5+7;
#define il inline
#define vocaloid(v) (v>='0'&&v<='9')
template <typename T>
il void read(T &x)
{
	x=0;char v=getchar();
	while(!vocaloid(v)) v=getchar();
	while(vocaloid(v)) {x=(x<<1)+(x<<3)+v-'0';v=getchar();}
}
template <typename T>
il void write(T x) {if(x>9) write(x/10); putchar(x%10+'0');}
template <typename T>
il void print(T x) {write(x); putchar('
');}
il int Max(int x,int y) {return x>=y?x:y;}
struct mission{
	int r,co,pos;
}Te[N];
struct Day{
	int t,pos;
}d[M];
int n,m,ans[N];
int c1[M],c2[M],t[M];
il bool cmp1(Day x,Day y) {return x.t==y.t?x.pos<y.pos:x.t>y.t;}
il bool cmp2(mission x,mission y) {return x.r==y.r?x.co<y.co:x.r>y.r;}
il int lowbit(int x) {return x&(-x);} 
il void change(int *c,int x,int val)
{
	for(int i=x;i<=m;i+=lowbit(i))
		c[i]+=val;
}
il int ask(int *c,int x)
{
	int ans=0;
	for(int i=x;i;i-=lowbit(i))
		ans+=c[i];
	return ans;
}
int main()
{
	freopen("work.in","r",stdin);
	freopen("work.out","w",stdout);
	read(n),read(m);
	for(int i=1;i<=m;i++)
	{
		read(t[i]);
		d[i]=(Day){t[i],i};
	}
	for(int i=1;i<=n;i++)
	{
		read(Te[i].r),read(Te[i].co);
		Te[i].pos=i;
	}
	sort(d+1,d+1+m,cmp1);
	sort(Te+1,Te+1+n,cmp2);
	int IA=1;
	for(int i=1;i<=n;i++)
	{
		for(;IA<=m&&d[IA].t>=Te[i].r;++IA)
			change(c1,d[IA].pos,d[IA].t),
			change(c2,d[IA].pos,1);
		int sum=ask(c1,m)-ask(c2,m)*Te[i].r;
		if(sum<Te[i].co) {ans[Te[i].pos]=0; continue ;}
		int l=1,r=m,mid;
		while(l<=r)
		{
			mid=(l+r)>>1;
			sum=ask(c1,mid)-ask(c2,mid)*Te[i].r;
			if(sum>=Te[i].co) r=mid-1;
			else l=mid+1;
		}
		ans[Te[i].pos]=l;
	}
	for(int i=1;i<=n;i++)
		write(ans[i]),putchar(' ');
	return 0;
}
原文地址:https://www.cnblogs.com/MIKU5201314/p/14086763.html