描述
输入 n 个整数,在所有连续且长度为K的区间中,找到最大的区间和。
输入描述
第一行包括两个整数 n 和 K。
第二行包括 n 个整数。
输出描述
输出两行。第一行一个整数,表示最大区间和。
第二行两个整数,表示最大区间和的起点下标和终点下标。
答案
#include<bits/stdc++.h>
using namespace std;
int a[5000001]={};
int s[5000001]={};
int main(){
int n,K;
cin>>n>>K;
for(int i=1;i<=n;i++){
//TODO
cin>>a[i];
}
s[1]=a[1];
for(int i=2;i<=n;i++){
//TODO
s[i]=s[i-1]+a[i];
}
int res=0;
int b,e;
for(int i=K;i<=n;i++){
//TODO
int t=s[i]-s[i-K];
if(t>res){
//TODO
res=t;
b=i-K+1;
e=i;
}
}
cout << res << endl;
cout << b << " " << e << endl;
return 0;
}
答案解析
1. 头文件包含和命名空间声明
#include<bits/stdc++.h>
using namespace std;
#include<bits/stdc++.h>
:这是一个非标准但被广泛使用的头文件,它实际上包含了 C++ 中大多数常用的标准库头文件(如<iostream>
、<vector>
、<algorithm>
等),方便在编写代码时可以直接使用各种标准库提供的功能,而不用逐个去包含对应的具体头文件。不过在一些严格的编译环境或者竞赛规则中,可能不允许使用这个头文件,更推荐按照实际需求分别包含具体的标准库头文件。using namespace std;
:声明使用std
命名空间。C++ 标准库中的类、函数、对象等大多定义在std
命名空间下,通过这行声明,后续代码中使用标准库的相关内容时就可以省略std::
前缀,使代码书写更简洁,但也存在一定的命名冲突风险(如果自定义的名称和std
里的重名了)。
2. 全局数组定义
int a[5000001]={};
int s[5000001]={};
这里定义了两个整型数组a
和s
,数组大小都为5000001
,并且都进行了初始化,将所有元素初始化为0
。通常这样大的数组在程序中可能用于存储较多的数据,比如a
数组可能用于存放输入的一系列数值,s
数组往往用于存储某种前缀和相关的数据(从后续代码逻辑来看是这样的用途)。
3. main
函数部分
- 输入数据部分:
int n,K;
cin>>n>>K;
for(int i=1;i<=n;i++){
//TODO
cin>>a[i];
}
-
首先定义了两个整型变量
n
和K
,n
大概率用于表示后续要输入的数据个数,K
可能是一个用于控制计算范围或者窗口大小之类的参数(从后面代码逻辑推断)。 -
然后通过
cin
从标准输入读取用户输入的n
和K
的值。 -
接着使用
for
循环,循环n
次,每次从标准输入读取一个整数并存入a
数组中,这样就将一系列的输入数据存储到了a
数组中。 -
计算前缀和部分:
s[1]=a[1];
for(int i=2;i<=n;i++){
//TODO
s[i]=s[i-1]+a[i];
}
这段代码用于计算数组a
的前缀和并存储到数组s
中。具体来说,首先将s[1]
初始化为a[1]
,然后从i = 2
开始循环到n
,对于每个i
,s[i]
的值等于前一个位置的前缀和s[i - 1]
加上当前位置a
数组中的元素a[i]
,这样经过循环后,s
数组中就存储了对应位置的前缀和信息,例如s[3]
就表示a[1] + a[2] + a[3]
的和。
- 寻找最大子段和(滑动窗口方式)部分:
int res=0;
int b,e;
for(int i=K;i<=n;i++){
//TODO
int t=s[i]-s[i-K];
if(t>res){
//TODO
res=t;
b=i-K+1;
e=i;
}
}
-
首先定义了三个变量,
res
用于存储找到的最大子段和,初始化为0
;b
和e
可能用于记录最大子段和对应的区间的起始和结束位置(从后面代码看确实如此)。 -
然后有一个
for
循环,从i = K
开始到n
结束,这里的K
就是前面输入的那个参数,循环的目的是以长度为K
的滑动窗口去遍历数组(基于前缀和来操作)。在每次循环中:- 计算当前窗口内的子段和,通过
s[i] - s[i - K]
来得到,即当前位置的前缀和减去窗口起始位置前一个位置的前缀和,这样就得到了长度为K
的窗口内元素的和,存储在变量t
中。 - 接着判断这个和
t
是否大于当前记录的最大子段和res
,如果大于,就更新res
为t
,同时更新b
为当前窗口的起始位置(即i - K + 1
),e
为当前窗口的结束位置(即i
)。
- 计算当前窗口内的子段和,通过
-
输出结果部分:
cout << res << endl;
cout << b << " " << e << endl;
最后,将找到的最大子段和res
输出到标准输出,然后输出对应的最大子段和区间的起始位置b
和结束位置e
,中间用空格隔开,方便查看最终的计算结果。
总的来说,这段代码的功能大致是输入一组数据,先计算其前缀和,然后通过滑动窗口的方式,利用前缀和去寻找长度为K
的子段中的最大和,并输出最大和以及对应的子段区间。 不过需要注意的是,代码中有些地方写了//TODO
注释,可能意味着这些地方后续还有完善或者添加其他逻辑的需求,当前代码只是实现了核心的上述功能。另外,在实际使用中,要确保输入的数据合法性以及考虑数组大小是否可能会导致栈溢出等问题(毕竟定义了较大的数组)。