2020超长寒假【gmoj2182】【eat羊羊吃草】【类似前缀和】

题目描述

小羊们上完课后,纷纷到草场上吃草。而羊村现在正在进行特色示范羊村检查,领导们想看看羊村的草场。
羊村的草场是连续分布的,每块草场上都有数量不等的羊在吃草。领导们想要查看连续若干个草场,但是又不想看到超过T只羊。而村长希望领导们多看看羊村的风貌,尽可能多参观几个草场。
现在,请你帮村长决定,带领导们去参观哪一段草场,满足领导和村长的要求。

输入

第一行一个整数N和T,表示羊村共有多少个连续草场,以及领导们希望看到羊数量的最大值。
第二行N个整数,两个整数间用一个空格分开,第i个数ai表示第i个草场上有ai只羊在吃草。编号从1到N。

输出

输出一行,共两个数,表示参观的起点编号和终点编号,中间用空格分开。走的方向总是从编号小的到编号大的。另外,若有长度相同的可能性,输出起点编号较小的答案。数据保证至少有答案存在。

样例输入

5 10
6 3 2 1 7

样例输出

2 4
数据范围限制

30%的数据,1<=N<=100;
60%的数据,1<=N<=1000;
100%的数据,1<=N<=100000, 0<=ai<=109,0<=T<=231-1。

提示

要满足连续个总和不超过10,有3+2+1和2+1+7两种可能性,优先输出2到4个草场。

分析

先说说70pts的做法:直接前缀和之后二重循环枚举每一个区间,再比较。
代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
ll n,a[100010],t,mx,mi,mj;
int main()
{
    freopen("eat.in","r",stdin);
	freopen("eat.out","w",stdout);
	scanf("%d%d",&n,&t);
	for(register int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		a[i]=a[i-1]+a[i];
	}
	for(register int i=1;i<=n-1;i++)
	{
		for(register int j=n;j>=i+1;j--)
		{
			if(a[j]-a[i-1]<=t)
			{
				if(j-i+1>mx)
				{
					mx=j-i+1;
					mi=i;
				    mj=j;
				    break;
				}
			}
		}
		if(n-i<=mj-mi) break;
	}
	printf("%d %d",mi,mj);
	fclose(stdin);
	fclose(stdout); 
    return 0;
}

正解:
这题的本质就是权值不大于t的最长连续序列。
用一种类似前缀和的方法,暴力一下加点优化,完事。

上代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long n,m,j,x,y,sum,a[100100];
int main()
{
	freopen("eat.in","r",stdin);
	freopen("eat.out","w",stdout);
	cin>>n>>m; 
	int j=1;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		sum+=a[i];
		while(sum>m)//保证当前草场可以参观
		{
			sum-=a[j++];
		}
		if(i-j+1>y-x+1)
		{
			x=j;
			y=i;
		}		
	}
	cout<<x<<' '<<y;
} 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值