#10006. 「一本通 1.1 练习 2」数列分段

版权声明:有女朋友的老江的博客,转载请告知老江 https://blog.csdn.net/qq_42367531/article/details/84259507

【题目描述】

对于给定的一个长度为 N 的正整数数列 Ai,现要将其分成连续的若干段,并且每段和不超过 M(可以等于 M),问最少能将其分成多少段使得满足要求。

【输入格式】

第一行包含两个正整数 N,M,表示了数列 Ai​ 的长度与每段和的最大值;

第二行包含 NNN 个空格隔开的非负整数 Ai。

【输出格式】

输出文件仅包含一个正整数,输出最少划分的段数。

【样例输入】

5 6
4 2 4 5 1

【样例输出】

3

【数据范围与提示】

对于 20%的数据,有N≤10;

对于 40% 的数据,有N≤1000;

对于 100% 的数据,有 N≤10^5, M≤10^9,MMM 大于所有数的最大值,Ai之和不超过10^9。

思路:啊呀,这绝对是我做loj的贪心以来最简单的一道题目了,话不多说。说实在的这道题我一看到就想到了dp,(无奈挠额头的表情),后面想了一下,其实用贪心更简单,直接模拟判断就好了。

判断有两个:

1.判断a[i]的值加起来是否比m大

2.判断如果加起来比m大,ans++

3.判断最后的单独一组

是不是简单的一批,真的很简单的啦,其实我觉得就是局部最优解,就是我们要尽可能的使a[i]+起来的值与m最接近,解释完毕,就这么简单。

【代码实现一:详解版】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()//日常快读 
{
	char c=getchar();
	int x=0,f=1;
	while(c<48 || c>57)
	{
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>=48 && c<=57)
	{
		x=x*10+c-48;
		c=getchar();
	}
	return x*f;
}
int a[110000];
int main()
{
	int n,m; n=read(); m=read();
	for(int i=1;i<=n;i++) a[i]=read();
	int sum=0;//sum是用来记录当前累积的数的总和 
	int ans=0;//ans是用来记录可以成立的组合 
	for(int i=1;i<=n;i++)
	{
		if(sum+a[i]<=m) sum+=a[i];
		/*
			如果当前sum+a[i]的值小于m,就是他的组合和的限值的话
			就把sum更新为当前的a[i]
			为什么要进行这一步呢,因为题目要求的是最少的组合
			所以我们要尽量是组合和尽可能大 
			所以这里不能直接加,而是要累加,再判断 
		*/ 
		else//如果sum+a[i]>m的话,说明我们可以把前面的消除,答案+1 
		{
			ans++;//答案+1 
			sum=a[i];//把前面的清零,从当前的这个a[i]继续往下算
			/*
				注意很多人容易忘掉这一步,这一步不可以少
				因为这一步代表的就是说我们把前面的清掉
				是代表前面的成为一组,跟当前我们循环到的这个a[i]
				没有半点关系
				所以sum一定一定要更新为a[i]
				再用当前的a[i]去组合
				比如说
				4 2 4 m的值为6
				那么我们4+2+4跳到了else这一步
				所以我们知道他们的组合不是 4 2 4
				而是4 2,所以就要把最后的4留下,其他的换为ans++ 
			*/ 
		}
	}
	if(sum!=0) ans++;
	/*
		这一步是我重点讲解的,前面的都很好理解
		这一步是什么意思呢?
		就是说我们一直组合组合,发现组合到最后的那一组的时候
		就是剩下的时候,电脑不会给我们自动ans++
		按常理最后剩下没组合的要自己一个一组
		所以这里我们就要判断
		如果按照了前面的之后,i已经没有的时候
		但是还有数而且比m小的时候
		我们就要单独判断sum剩下的值,不是0的话说明还要自成一组,ans++
		
		就拿样例来说吧
		5 6
		4 2 4 5 1
		前面的4 2先判断成了一组
		然后4 5的时候成了一组
		这个时候sum的值为5,到i=5,a[i]=1
		但是5+1=6,没有大于m,所以sum这时变成了6
		但实际上这是要成为一组的
		所以我们就要在这里判断剩下的sum值
		剩下了,就ans++,答案加一,组合加一 
	*/
	printf("%d\n",ans);//输出答案 
	return 0;
}

【代码实现二:小小的变化】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()
{
	char c=getchar();
	int x=0,f=1;
	while(c<48 || c>57)
	{
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>=48 && c<=57)
	{
		x=x*10+c-48;
		c=getchar();
	}
	return x*f;
}
int a[110000];
int main()
{
	int n,m; n=read(); m=read();
	for(int i=1;i<=n;i++) a[i]=read();
	int sum=0;
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		if(sum+a[i]<=m) sum+=a[i];
		else
		{
			ans++;
			sum=a[i];
		}
	}
	printf("%d\n",ans+1);//代表最后的组合 
	return 0;
}

表示蒟蒻并不知道为什么第二个代码会比第一个代码多了2ms秒 

猜你喜欢

转载自blog.csdn.net/qq_42367531/article/details/84259507
今日推荐