列表

详情


NC54257. 能否购买

描述

zzz即将过生日,NQ想要送他一份生日礼物,正巧碰上蛋糕店做活动,NQ义无反顾参与其中。

蛋糕店店长给出一个长度为 n 的整数序列,并另外给出 m 个数,对于这每一个数 b,需要NQ判断是否能在原序列中找出一段长度不超过 k 的连续序列,使其各元素之和大于等于 b。

若对于这 m 个数,NQ都能回答正确,则将获得一折购买大蛋糕的优惠,但是NQ不会做这题,所以向致力于 ACM 的你求助,希望能够一起给zzz过生日。

输入描述

第一行输入三个用空格隔开的整数 n, m, k,具体含义如题所述。
第二行一共 n 个整数 ai,表示这个序列中第 i 个元素的值。
接下去 m 行,每行一个整数 b,表示询问。
1 ≤ n, m, k ≤ 106, |ai| ≤ 103, |b| ≤ 109

输出描述

对于每一个整数 b,如果原序列 a 中存在满足题意要求的序列,则输出 "YES", 否则输出 "NO".(均不包含引号)

示例1

输入:

5 3 2
1 -1 2 3 -2
1
5
6

输出:

YES
YES
NO

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 425ms, 内存消耗: 8044K, 提交时间: 2019-10-24 20:26:12

# include <iostream>	// NQ
# include <cstdio>
# include <algorithm>

using namespace std;

const int N = 1e6 + 5;
int n, m, k, sum[N];
int q[N], hh, tt;

int main()
{
	scanf("%d %d %d", &n, &m, &k);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &sum[i]);
		sum[i] += sum[i - 1];
	}
	int max_res = -0x3f3f3f3f;
	for (int i = 1; i <= n; i++) {
		if (hh <= tt && i - q[hh] > k)
			hh++;
		max_res = max(max_res, sum[i] - sum[q[hh]]);
		while (hh <= tt && sum[i] <= sum[q[tt]])
			tt--;
		q[++tt] = i;
	}
	while (m--) {
		int x;
		scanf("%d", &x);
		if (max_res >= x)
			printf("YES\n");
		else
			printf("NO\n");
	}
	return 0;
}

C++14(g++5.4) 解法, 执行用时: 416ms, 内存消耗: 20188K, 提交时间: 2019-10-25 22:58:26

#include<cstdio>
#include<algorithm>
using namespace std;
int s[1000005],q[1000005];
int main()
{
	int n,m,k;
	scanf("%d%d%d",&n,&m,&k);
	int head=1,tail=0;
	s[0]=0;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&s[i]);
		s[i]+=s[i-1];
	}
	int maxn=-999999;
	
	for(int i=1;i<=n;i++)       /*构造单调队列来做长度为 k 的滑动窗口*/
	{
		while(head<=tail&&q[tail]-q[head]>k) /*滑动窗口队首进位*/ 
		head++;
		while(head<=tail&&s[i]<s[q[tail]])       /*维护单调递增队列:新进的元素若小于队列尾元素,则队尾舍弃*/
		tail--;
		q[++tail]=i;
		maxn=max(s[i]-s[q[head]],maxn);
		
		    
	}
	while(m--)
	{
		int b;
		scanf("%d",&b);
		maxn>=b?printf("YES\n"):printf("NO\n");
		
	}
	
}

上一题