1497最小和

该题转载自http://smoj.nhedu.net/showproblem?id=1497

最小和(小学测试6)

题目描述

输入N个数的数列,所有相邻M数的和有N-M+1个,求其中的最小值。

输入格式  1497.in

第一行,2个整数N、M,范围在[3…100000], N > M。
第二行,有N个正整数,每个数的范围在[1…1000]。

输出格式  1497.out

一个数。

输入样例  1497.in
6 3
10 4 1 5 5 2
输出样例  1497.out

10
解释:连续3个数的和有4个,分别是
10+4+1=15, 4+1+5=10
1+5+5=11, 5+5+2=12
其中最小的是10

首先看到这道题,我心里第一个想法就是枚举计算和,这很简单

先开一个数组,(n个数据,n的范围在3至100000之间)——int t[100005]

然后填入数据

从第i个至第m+i-1个求累加和(i<=n-m+1 //因为最后一个不可以和后m个求累加和,(后m个都是0)所以最后只能求(总数-区间总数+1)个到最后一个的和)

for(int i=1;i<=n-m+1;i++)
	{
		int s=0;//累加变量 
		for(int j=i;j<=i+m-1;j++)
		{
			s=s+t[j];//累加 
		}
		if(s<mins)
		{
			mins=s;//判断是否小于当前最小值 
		}
	}

结果输出



果不其然,超时了(答案错误什么鬼)

让我们算一下为什么超时:

嗯~

10^8就会超时

而数据量。。。。。。

假设n=100000,m=10000 {

那么需要(100000-10000+1)*10000次=900010000次(10^8)

}

绝对超时啊

解决方法:(枚举优化)

{

for循环超时怎么办?

当然是找出for语句所做的不必要的功并剔除就行了~

我们的双for中循环最多的自然是求累加和了

那么,有没有这样一种方法,将所要求的和提前求出来保存到数组中,就不必再求一次累加和了

绝对有的。。。。。。

          {(注:此处受老师点拨)

          假设n=6,m=3,数据分别为3,1,4,5,9,7

          那么按照我们原来的方法——首先求3+1+4=8,接着求1+4+5=10,再接着求4+5+9=18

          发现了什么?(不是第一个+第二个=第三个啊!)

          3,1,4           1,4,5        4,5,9

          这9个数有重复

          也就是说:1+4+5的和可以分解为上一区间和3+1+4的和-3+5!

          那么借助这个方法,我们可以简便的求出累加和了(1+4+5=3+1+4-3+5)

                     假设m=3

                     {

                      求累加和重新定一个数组,int f[100005]

                       为了好看点,我写在函数里

void lt(int f[])
{
	int s=0;//并没有什么用的变量,用来求第一个累加和 
	for(int i=1;i<=m;i++)
	{
		s=s+t[i]; 
	}
	f[1]=s;//第一个赋值 
    int h=1,l=h+m,i=2;
    while(l<=n)
    {
    	f[i]=f[i-1]-t[h]+t[l];
    	h++;
    	l=h+m;
    	i++;
	}
} 
其中h指所要删去的值的下标,l指所要加上的值的下标

仔细解释一下:

刚刚我们假设了6个值:3 1 4 5 9 7

F数组中:    f[1]=3+1+4=8              f[2]=3+1+4  -3  +5 ......

其中3+1+4是f[1]已经求出的值,所以3+1+4可以表示为f[1]

       同理,f[3],f[4]......中的可以表示为f[2],f[3]......

               也就是说,f[i]中的部分值可以用f[i-1]表达

                       即这一区间的和=上一区间的和+下一个数的和-上一个数的和

f[1]=3+1+4      f[2]=f[2-1]   -3   +5

减去的值3既是数组t中的第一个 那么,h=1

加上的值5是数组t中的第四个 那么,l=4      4=1+m(m=3)    所以:l=h+m

f[1]=3+1+4     f[2]=f[2-1]-t[1]+t[1+3] 

     f[3]=f[3-1]    -1   +9

减去的值1既是数组t中的第二个 那么,h=h+1=2

加上的值5是数组t中的第五个 那么,l=5   5=h(h=2)+m(m=3)    所以:l=h+m

最后必不可少的自然是i++;//数组f的操作数

                  完整代码:

#include<iostream>
#include<stdio.h>
using namespace std;
int n,m,t[100005],mins=100000005;//mins尽量定大些 
void lt(int f[])
{
	int s=0;//并没有什么用的变量,用来求第一个累加和 
	for(int i=1;i<=m;i++)
	{
		s=s+t[i]; 
	}
	f[1]=s;//第一个赋值 
    int h=1,l=h+m,i=2;
    while(l<=n)
    {
    	f[i]=f[i-1]-t[h]+t[l];
    	h++;
    	l=h+m;
    	i++;
	}
} 
int main()
{
	freopen("1497.in","r",stdin);
	freopen("1497.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&t[i]);
	}
	int f[100005];
	for(int i=1;i<=n+1;i++)//初始化数组f=-1 
	   f[i]=-1;//为以后找最小值判断结束条件做准备 
	lt(f);
	/*for(int i=1;i<=n-m+1;i++)
	{
		int s=0;//累加变量 
		for(int j=i;j<=i+m-1;j++)
		{
			s=s+t[j];//累加 
		}
		if(s<mins)
		{
			mins=s;//判断是否小于当前最小值 
		}
	}*/
	int i=1;
	while(f[i]!=-1)//看前面的数组f赋初值就懂了 
	{
		mins=min(mins,f[i]);//min是头文件iostream中的一个比较多个数最小值的函数 
		i++;
	}
	printf("%d",mins);	
    return 0;
}

终于做对la~

                     }

}

这也意味着:1497告一段落了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值