小明这些天一直在思考这样一个奇怪而有趣的问题:
在 1∼N 的某个排列中有多少个连号区间呢?
这里所说的连号区间的定义是:
如果区间 [L,R] 里的所有元素(即此排列的第 L 个到第 R 个元素)递增排序后能得到一个长度为 R−L+1 的“连续”数列,则称这个区间连号区间。
当 N 很小的时候,小明可以很快地算出答案,但是当 N 变大的时候,问题就不是那么简单了,现在小明需要你的帮助。
输入格式
第一行是一个正整数 N,表示排列的规模。
第二行是 N 个不同的数字 Pi,表示这 N 个数字的某一排列。
输出格式
输出一个整数,表示不同连号区间的数目。
数据范围
1≤N≤10000,
1≤Pi≤N
输入样例1:
4
3 2 4 1
输出样例1:
7
输入样例2:
5
3 4 2 5 1
输出样例2:
9
样例解释
第一个用例中,有 7 个连号区间分别是:[1,1],[1,2],[1,3],[1,4],[2,2],[3,3],[4,4]
第二个用例中,有 9 个连号区间分别是:[1,1],[1,2],[1,3],[1,4],[1,5],[2,2],[3,3],[4,4],[5,5]
当然,下面是带有详细注释的暴力解法代码:
cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 辅助函数,用于检查一个区间内的数是否连续
bool isContinuous(vector<int>& segment) {
// 对区间内的数进行排序
sort(segment.begin(), segment.end());
// 遍历排序后的区间,检查是否每个数都是前一个数加1
for (int i = 1; i < segment.size(); ++i) {
if (segment[i] != segment[i - 1] + 1) {
return false; // 如果不是连续的,返回false
}
}
return true; // 如果所有数都是连续的,返回true
}
int main() {
int N;// 输入排列的大小
cin >> N;
vector<int> P(N);
// 输入排列的每个元素
for (int i = 0; i < N; ++i) {
cin >> P[i];
}
int count = 0;
// 外层循环遍历区间的起始位置
for (int i = 0; i < N; ++i) {
// 内层循环遍历区间的结束位置
for (int j = i; j < N; ++j) {
// 创建一个区间,从P[i]到P[j]
vector<int> segment(P.begin() + i, P.begin() + j + 1);
// 检查这个区间是否连续
if (isContinuous(segment)) {
count++; // 如果是连续的,增加计数器
}
}
}
// 输出不同连号区间的数目
cout << count << endl;
return 0;
}
这段代码的注释解释了每行代码的作用和功能。这种暴力解法在 N 较小时是可行的,但是当 N 增大时,由于时间复杂度较高,程序运行会变得非常慢。在实际应用中,我们通常会寻找更高效的算法来解决这个问题。