P8508 做不完的作业 验题人题解

我是验题人。我和出题人的两种贪心其实不大一样,然后有挺多人反应看不懂我的代码,原因是 5ab 把我的巨丑代码挂到题解上去了。

首先说一说贪心。我的贪心是:按顺序考虑每个任务,每个任务安排在其最早能放的那一天。

有人可能有疑惑:有可能第 \(x\) 天原本安排的其中一个任务 \(y\),将其替换为睡觉,将任务 \(y\) 往后推,会不会更优。事实上是不会的:如果你把 \(y\) 推到了 \(x+1\) 天,那么你有可能会增多一天消耗,但是对于第 \(x+1\) 天及以后的天,你没有增加任何的前缀睡觉时间(因为做任务的总量恒定,睡觉量也恒定)。所以不可能减少一天。

然后怎么写这个贪心。直接模拟?很遗憾,被毒瘤的出题人卡掉了,你会 TLE 几个点。因为直接模拟你需要模拟每一天的情况,这样的复杂度和总天数相关。所以我们需要加一个小优化:对于一个任务,如果你需要先睡好几天才能完成它,那么计算出睡的天数,而不一天一天地模拟。

容易发现这样的复杂度是线性的。

在计算天数的时候,可能需要稍微推一下式子,接下来是一些简单的推导。

以下用 \(m\) 表示一天的总时间,与题面不同。假设当前面对的是第 \(tot\) 个任务,需要 \(a_{tot}\) 的时间,目前总睡觉时间是 \(sl\),现在是第 \(j\) 天。那么当 \(m-a_{tot}+sl<m⋅j⋅\dfrac{p}{q}\) 的时候,这一天内肯定完成不了任务。我们计算需要连续睡几天觉,假设要再睡 \(i\) 天,那么有 \(m-a_{tot}+sl+i⋅m\ge m⋅(i+j)⋅\dfrac{p}{q}\),简单移项可得:\(i\ge \dfrac{j⋅m⋅p-q⋅(m-a_{tot}+sl)}{m⋅(q-p)}\),取最小的 \(i\) 即可。

稍微修缮了一下的代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1000005;
ll n,m,p,q; 
ll a[N];

int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cin >> n >> m >> p >> q;
	for (int i=1;i<=n;i++) cin >> a[i];
	ll tot=1,sl=0;
	for (ll j=1;;j++)
	{
		if ((m-a[tot]+sl)*q<m*p*j)
		{
			ll i=(m*p*j-(m-a[tot]+sl)*q+(m*(q-p))-1)/(m*(q-p));
			j+=i,sl+=i*m;
		}
		ll x=m;
		while (1)
		{
			if (tot==n+1) break;
			if (x<=a[tot]) break;
			if ((x-a[tot]+sl)*q<m*p*j) break;
			x-=a[tot],tot++;
		}
		sl+=x;
		if (tot==n+1)
		{
			cout << j;
			return 0;
		}
	}
	return 0;
}
posted @ 2022-09-07 21:24  Little09  阅读(86)  评论(0编辑  收藏  举报