Loading

非严格单调栈 + 山峰数组

有效序列的数量
我们定义一个有效序列为:该序列两端的数一个为最小值,另一个为次小值。(即序列两端以外的数一定大于等于最左边的数且大于等于最右边的数)

现在给你一个序列 a ,想让你找到它的连续子序列中有多少个有效序列(比如 ,1 2 ,2 3,1 2 3 是序列 1 2 3 的连续子序列,但是 1 3 不是)

注:长度为 2 的子序列,一定为有效序列,长度为 1 的子序列,一定不是有效序列
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 256M,其他语言512M
输入描述:
第一行输入一个整数 n 代表这个序列的长度
接下来输入 n 个整数,a[i] 代表系列中第 i 个元素

对于 20% 的数据, 1 ≤ n ≤ 100
对于 70% 的数据, 1 ≤ n ≤ 3,000
对于 100% 的数据, 1 ≤ n ≤ 100,000

对于 100% 的数据, 1 ≤ a[i] ≤ 1,000,000,000
输出描述:
输出一个正整数表示有效序列的数量。
示例1
输入例子:
4
1 3 1 2
输出例子:
4
例子说明:
一共有 4 组有效序列,分别为:
子序列[1,3] 因为长度为 2,一定为有效序列
子序列[1,3,1] 因为第2个数 “3” 大于第 1 个数和第 3 个数
子序列[3,1] 因为长度为 2,一定为有效序列
子序列[1,2] 因为长度为 2,一定为有效序列
示例2
输入例子:
4
1 1 2 1
输出例子:
5
例子说明:
一共有6个长度不小于2的连续子序列,除了[1,1,2]以外,其他5个都是有效子序列
示例3
输入例子:
7
1 4 2 5 7 1 3
输出例子:
10
例子说明:
一共有10组,分别为:
[1,4], [1,4,2], [1,4,2,5,7,1], [4,2], [2,5], [2,5,7,1], [5,7], [5,7,1], [7,1], [1,3]

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n, a[100005];
ll ans = 0;
int main() {
  ios::sync_with_stdio(0), cin.tie(0);
  int i, j;
  cin >> n;
  for (i = 1; i <= n; i++) cin >> a[i];
  stack<int> st;
  unordered_map<int, int> dup_count;
  ll res = 0;
  for (int i = 1; i <= n; i++) {
    // 最小值,寻找左侧严格大于本元素的索引
    while (!st.empty() && a[i] < a[st.top()]) {
      int cur = st.top();
      st.pop();
      res += dup_count[a[cur]];
      dup_count[a[cur]] = 0;  // 重置
    }
    // 找不到
    if (st.empty()) {
      dup_count[a[i]] = 1;
      st.push(i);
    } else {  // 次小值,寻找左侧不严格大于本元素的索引
      if (a[st.top()] == a[i]) {  // 遇到相等元素
        res += dup_count[a[i]];
        // 重要!当遇到重复值时,我们可以尝试继续尝试向深入一步
        if (st.size() > 1) {
          res += 1;
        }
        // 并入
        dup_count[a[i]]++;
      } else {  // 遇到严格小于本元素的值
        res += 1;
        dup_count[a[i]] = 1;
        st.push(i);
      }
    }
  }
  cout << res;
  return 0;
}
posted @ 2023-03-17 22:56  ZXYFrank  阅读(130)  评论(0编辑  收藏  举报