题目
注册账号邀请码:
https://bs.daimayuan.top/?invitor=2833
复制粘贴即可~
填我的哟,这样算我的邀请次数 😃
题目分析
其实,通过仔细分析题目,其实就是求 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an 中长度小于等于 m + 1 m+1 m+1 的最大子段和。
代码历程
1版
聪明的你想到了用暴力枚举解题。
// 关于训练不用万能头这件事。。。
#include <iostream>
#include <cstdio>
using namespace std;
int n, m, a[5001], x, y; // n <= 5000,a 开 5001
int main () {
scanf("%d%d", &n, &m), m++; // 长度最多 m+1 的最大子段和
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
for (int i = 1; i <= m; i++) // 定下子段和长度
for (int j = 1; j + i - 1 <= n; j++) { // 定下起点
y = 0;
for (int k = j; k <= j + i - 1; k++) y += a[k]; // 求这个子段的和
x = max(x, y); // 更新值
}
printf("%d\n", x);
return 0;
}
2版
测试点 #1-5 WA,聪明的你想到了特判 n = 1 n=1 n=1 的时候。
#include <iostream>
#include <cstdio>
using namespace std;
int n, m, a[5001], x, y;
int main () {
scanf("%d%d", &n, &m), m++;
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
if (n == 1) { // 出题人的小心思。。。
printf("%d\n", a[1]);
return 0;
}
for (int i = 1; i <= m; i++)
for (int j = 1; j + i - 1 <= n; j++) {
y = 0;
for (int k = j; k <= j + i - 1; k++) y += a[k];
x = max(x, y);
}
printf("%d\n", x);
return 0;
}
太好了,TLE。
这段代码 n ≤ 5000 n\le5000 n≤5000,我们的时间复杂度大概在 O ( n 3 ) O(n^3) O(n3) 左右(比它小),也就是 O ( 75000000000 ) O(75000000000) O(75000000000)( O ( 750 亿 ) O(750亿) O(750亿),即使比它小也小不到哪里去), 1 s 1s 1s 内肯定出不了结果。
3版
聪明的你想到了前缀和。
#include <iostream>
#include <cstdio>
using namespace std;
int n, m, a[5001], x, y;
int main () {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]), a[i] += a[i - 1]; // 直接覆盖 a 数组没事的
if (n == 1) {
printf("%d\n", a[1]);
return 0;
}
for (int i = 1; i <= n; i++) // 依旧枚举,不会超时
for (int j = i; j <= min(n, i + m); j++)
x = max(x, a[j] - a[i - 1]);
printf("%d\n", x);
return 0;
}
AC,太棒了。
时间复杂度 O ( n + n 2 ) O(n+n^2) O(n+n2)。
完结
撒草。。。


被折叠的 条评论
为什么被折叠?



