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

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

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

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

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

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

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

以下用 m 表示一天的总时间,与题面不同。假设当前面对的是第 tot 个任务,需要 atot 的时间,目前总睡觉时间是 sl,现在是第 j 天。那么当 matot+sl<mjpq 的时候,这一天内肯定完成不了任务。我们计算需要连续睡几天觉,假设要再睡 i 天,那么有 matot+sl+imm(i+j)pq,简单移项可得:ijmpq(matot+sl)m(qp),取最小的 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 @   Little09  阅读(91)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类
点击右上角即可分享
微信分享提示