题目## 题目
题目链接
题目描述
小红有一个长度为 n − 1 n-1 n−1 的数组,满足 1 ≤ a i ≤ n 1 \leq a_i \leq n 1≤ai≤n 且 a i < a i + 1 a_i < a_{i+1} ai<ai+1,求顺子的最大长度。
顺子的定义为:对于长度为 m m m 的数组 b b b,如果 b i + 1 = b i + 1 b_i + 1 = b_{i+1} bi+1=bi+1( 1 ≤ i < m 1 \leq i < m 1≤i<m),则称 b b b 是顺子。
输入:
- 第一行一个整数 n n n,表示数组的长度加1
- 第二行 n − 1 n-1 n−1 个整数,表示严格递增的数组 a a a
输出:
- 一个整数,表示顺子的最大长度
解题思路
这是一个序列问题,可以通过以下步骤解决:
-
首先理解题目特点:
- 输入数组已经是严格递增的
- 不需要排序和去重
- 只需要找到连续递增(差值为1)的最长子序列
-
解题策略:
- 直接遍历数组
- 检查相邻两个数的差值是否为1
- 维护最长的连续序列长度
-
具体步骤:
- 遍历数组,检查相邻元素
- 如果 a [ i ] = a [ i − 1 ] + 1 a[i] = a[i-1] + 1 a[i]=a[i−1]+1,则当前连续序列长度加1
- 否则重新开始计数
- 维护最大长度
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n - 1);
for(int i = 0; i < n - 1; i++) {
cin >> a[i];
}
int maxLen = 1; // 最长顺子长度
int curLen = 1; // 当前顺子长度
// 遍历寻找连续序列
for(int i = 1; i < n - 1; i++) {
if(a[i] == a[i-1] + 1) {
curLen++;
maxLen = max(maxLen, curLen);
} else {
curLen = 1;
}
}
cout << maxLen << endl;
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n - 1];
for(int i = 0; i < n - 1; i++) {
a[i] = sc.nextInt();
}
int maxLen = 1; // 最长顺子长度
int curLen = 1; // 当前顺子长度
// 遍历寻找连续序列
for(int i = 1; i < n - 1; i++) {
if(a[i] == a[i-1] + 1) {
curLen++;
maxLen = Math.max(maxLen, curLen);
} else {
curLen = 1;
}
}
System.out.println(maxLen);
}
}
n = int(input())
a = list(map(int, input().split()))
max_len = 1 # 最长顺子长度
cur_len = 1 # 当前顺子长度
# 遍历寻找连续序列
for i in range(1, n - 1):
if a[i] == a[i-1] + 1:
cur_len += 1
max_len = max(max_len, cur_len)
else:
cur_len = 1
print(max_len)
算法及复杂度
- 算法:一次遍历
- 时间复杂度: O ( n ) \mathcal{O}(n) O(n) - 只需要遍历一次数组
- 空间复杂度: O ( n ) \mathcal{O}(n) O(n) - 需要存储输入数组
题目链接
题目描述
小红拿到了一个矩形的蛋糕,共分成了 n n n 行 m m m 列,共 n × m n \times m n×m 个区域,每个区域是一个小正方形,已知蛋糕每个区域都有一个美味度。
小红希望切割出一个正方形的小蛋糕(正方形边长必须平行于矩阵的边长,且必须都是完整的区域),自己吃掉正方形的部分,把剩下的部分给小紫吃。
小红希望两人吃的部分的美味度之和尽可能接近,小红吃的蛋糕美味度之和为 x x x,小紫吃的蛋糕美味度之和为 y y y,请你输出 ∣ x − y ∣ |x-y| ∣x−y∣ 的最小值。
输入:
- 第一行输入两个正整数 n n n 和 m m m,代表蛋糕区域的行数和列数
- 接下来 n n n 行,每行输入 m m m 个正整数,表示每个区域的美味度
输出:
- 一个整数,代表 ∣ x − y ∣ |x-y| ∣x−y∣ 的最小值
解题思路
这是一个枚举问题,可以通过以下步骤解决:
-
预处理:
- 计算整个蛋糕的总美味度 total
- 使用二维前缀和数组加速区域和的计算
-
枚举策略:
- 枚举正方形的边长 len(从1到min(n,m))
- 枚举正方形左上角的位置 (i,j)
- 计算正方形区域的美味度和剩余区域的美味度
- 更新最小差值
-
具体步骤:
- 构建二维前缀和数组
- 对每个可能的正方形大小和位置:
- 计算正方形区域的美味度和
- 计算剩余区域的美味度和
- 计算两者差值的绝对值
- 维护最小差值
代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n, m;
cin >> n >> m;
// 构建二维前缀和数组
vector<vector<ll>> sum(n + 1, vector<ll>(m + 1, 0));
ll total = 0;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
int x;
cin >> x;
total += x;
sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + x;
}
}
// 计算区域和的函数
auto getSum = [&](int x1, int y1, int x2, int y2) -> ll {
return sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1];
};
ll ans = total;
// 枚举正方形边长
for(int len = 1; len <= min(n, m); len++) {
// 枚举左上角位置
for(int i = 1; i + len - 1 <= n; i++) {
for(int j = 1; j + len - 1 <= m; j++) {
ll square = getSum(i, j, i + len - 1, j + len - 1);
ll remain = total - square;
ans = min(ans, abs(square - remain));
}
}
}
cout << ans << endl;
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
// 构建二维前缀和数组
long[][] sum = new long[n + 1][m + 1];
long total = 0;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
int x = sc.nextInt();
total += x;
sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + x;
}
}
long ans = total;
// 枚举正方形边长
for(int len = 1; len <= Math.min(n, m); len++) {
// 枚举左上角位置
for(int i = 1; i + len - 1 <= n; i++) {
for(int j = 1; j + len - 1 <= m; j++) {
int x1 = i, y1 = j;
int x2 = i + len - 1, y2 = j + len - 1;
long square = sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1];
long remain = total - square;
ans = Math.min(ans, Math.abs(square - remain));
}
}
}
System.out.println(ans);
}
}
import sys
input=sys.stdin.readline
n, m = map(int, input().split())
# 构建二维前缀和数组
sum = [[0] * (m + 1) for _ in range(n + 1)]
total = 0
for i in range(1, n + 1):
row = list(map(int, input().split()))
for j in range(1, m + 1):
total += row[j-1]
sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + row[j-1]
def get_sum(x1, y1, x2, y2):
return sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1]
ans = total
# 枚举正方形边长
for length in range(1, min(n, m) + 1):
# 枚举左上角位置
for i in range(1, n - length + 2):
for j in range(1, m - length + 2):
square = get_sum(i, j, i + length - 1, j + length - 1)
remain = total - square
ans = min(ans, abs(square - remain))
print(ans)
算法及复杂度
- 算法:二维前缀和 + 枚举
- 时间复杂度: O ( n 3 ) \mathcal{O}(n^3) O(n3) - 需要枚举正方形的大小和位置
- 空间复杂度: O ( n ⋅ m ) \mathcal{O}(n \cdot m) O(n⋅m) - 需要存储二维前缀和数组
1969

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



