该题转载自http://smoj.nhedu.net/showproblem?id=1497
输入N个数的数列,所有相邻M数的和有N-M+1个,求其中的最小值。
第一行,2个整数N、M,范围在[3…100000], N > M。
第二行,有N个正整数,每个数的范围在[1…1000]。
一个数。
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
结果输出
果不其然,超时了(答案错误什么鬼)
让我们算一下为什么超时:
嗯~
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
#include
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
}
}
这也意味着:1497告一段落了