1090. 绿色通道

题目链接

1090. 绿色通道

高二数学《绿色通道》总共有 \(n\) 道题目要抄,编号 \(1,2,…,n\),抄第 \(i\) 题要花 \(a\_i\) 分钟。

小 Y 决定只用不超过 \(t\) 分钟抄这个,因此必然有空着的题。

每道题要么不写,要么抄完,不能写一半。

下标连续的一些空题称为一个空题段,它的长度就是所包含的题目数。

这样应付自然会引起马老师的愤怒,最长的空题段越长,马老师越生气。

现在,小 Y 想知道他在这 \(t\) 分钟内写哪些题,才能够尽量减轻马老师的怒火。

由于小 Y 很聪明,你只要告诉他最长的空题段至少有多长就可以了,不需输出方案。

输入格式

第一行为两个整数 \(n,t\)

第二行为 \(n\) 个整数,依次为 \(a_1,a_2,…,a_n\)

输出格式

输出一个整数,表示最长的空题段至少有多长。

数据范围

\(0 < n \le 5 \times 10^4\),
\(0 < a_i \le 3000\),
\(0 < t \le 10^8\)

输入样例:

17 11
6 4 5 2 5 3 4 5 2 3 4 5 2 3 6 3 5

输出样例:

3

解题思路

二分,单调队列优化dp

显然,本题具有单调性,即要使最小的空题段越小,所用的时间越多,故可以考虑二分答案 \(x-1\),问题就可以转化为在连续的长度为 \(x\) 的区间内必须选上一个数,因为如果没有在这样的一个区间内选数的话,空题段就能为 \(x\),比 \(x-1\) 更大,不合二分,故问题就转化为 1087. 修剪草坪 单调队列优化dp模板题

  • 时间复杂度:\(O(nlogn)\)

代码

// Problem: 绿色通道
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/1092/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=5e4+5;
int n,t,a[N],q[N],hh,tt,f[N];
int ck(int x)
{
	hh=0,tt=0;
	for(int i=1;i<=n;i++)
	{
		f[i]=a[i];
		while(hh<=tt&&i-1-q[hh]+1>x)hh++;
		if(i>=x)f[i]+=f[q[hh]];
		while(hh<=tt&&f[q[tt]]>=f[i])tt--;
		q[++tt]=i;
	}
	int res=0x3f3f3f3f;
	for(int i=max(0,n+1-x);i<=n;i++)res=min(res,f[i]);
	return res<=t;
}
int main()
{
    scanf("%d%d",&n,&t);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    int l=1,r=n;
    while(l<r)
    {
    	int mid=l+r>>1;
    	if(ck(mid))r=mid;
    	else
    		l=mid+1;
    }
    printf("%d",l-1);
    return 0;
}
posted @ 2022-12-07 10:35  zyy2001  阅读(66)  评论(0编辑  收藏  举报