第一行输入一个整数 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
输出一个正整数表示有效序列的数量。
4 1 3 1 2
4
一共有 4 组有效序列,分别为:子序列[1,3] 因为长度为 2,一定为有效序列子序列[1,3,1] 因为第2个数 “3” 大于第 1 个数和第 3 个数子序列[3,1] 因为长度为 2,一定为有效序列子序列[1,2] 因为长度为 2,一定为有效序列
4 1 1 2 1
5
一共有6个长度不小于2的连续子序列,除了[1,1,2]以外,其他5个都是有效子序列
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]
arr:[1,1,2,1]
stack:[]
i=0,考察以arr[0]结尾,且以arr[0]为最小值的有效序列数,由于arr[0]的左边没有元素,所以直接入栈(为了考虑重复数字,需要记录某个数字的重复次数)
stack:[node(val=1,times=1)]
i=1,考察以arr[1]结尾,且以arr[1]为最小值的有效序列数,由于arr[0]=stack.top.val,直接压栈(与栈顶元素相同,增加栈顶元素的出现次数)
stack:[node(val=1,times=2)]
i=2,考察以arr[2]结尾,且以arr[2]为最小值的有效序列数,由于arr[2]>stack.top.val,直接压栈
stack:[node(val=1,times=2),node(val=2,times=1)]
i=3,考察以arr[3]结尾,且以arr[3]为最小值的有效序列数,而此时arr[3]<stack.top.val,破坏单调性,开始弹栈,栈顶元素为2,且只有一个2,说明可以与arr[3]构成一个有效的序列[2,1](刚好是以arr[3]结尾,且arr[3]为最小值,2为次小值)。
弹栈之后发现栈顶为1,且1出现了两次,可以与arr[3]构成两个有效序列,一个是①:[1,2,1],另一个是②:[1,1,2,1]。①中左边的1是把栈顶的2弹出后的次大值(由于栈是大压小的单调性,所以弹出2之后,如果栈顶元素仍然不小于arr[3],则栈顶元素一定可以作为次小值);同理②弹出的1也可以作为次小值。而两个1是同时弹出的,所以直接累加上2就可以了,此时已经有了[2,1],[1,2,1],[1,1,2,1]三个有效序列。
import java.io.*;
import java.util.*;
class Node {
public int value;
public int times;
public Node(int v, int t) {
value = v;
times = t;
}
}
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
if(n < 2){
System.out.println(0);
return;
}
String[] strs = br.readLine().split(" ");
int[] arr = new int[n];
for(int i = 0; i < n; i++){
arr[i] = Integer.parseInt(strs[i]);
}
long ans = 0;
Stack<Node> stack = new Stack<>();
for(int i = 0; i < n; i++){
while(!stack.isEmpty() && stack.peek().value > arr[i]){
Node topNode = stack.pop();
ans += topNode.times + cn2(topNode.times);
}
if(!stack.isEmpty() && arr[i] == stack.peek().value){
stack.peek().times++;
}else{
stack.push(new Node(arr[i], 1));
}
}
while(!stack.isEmpty()){
ans += cn2(stack.pop().times);
}
for(int i = n - 1; i >= 0; i--){
while(!stack.isEmpty() && stack.peek().value > arr[i]){
Node topNode = stack.pop();
ans += topNode.times;
}
if(!stack.isEmpty() && arr[i] == stack.peek().value){
stack.peek().times++;
}else{
stack.push(new Node(arr[i], 1));
}
}
System.out.println(ans);
}
private static long cn2(int n) {
return (long)n*(n - 1) >> 1;
}
} 思路:单调栈+dp
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
using namespace std;
const int maxsize = 100019;
int stk[maxsize], n, top = 0, dp[maxsize];
long long ans = 0;
int main()
{
int i, x, h, j;
cin >> n;
dp[0] = -1;
for (i = 0; i < n; i++)
{
cin >> x;
h = top;
while (top > 0 && stk[top - 1] > x)
{
top = dp[top - 1] + 1;
}
j = top - 1;
if (j > -1 && stk[j] == x) j = dp[j];
ans += h - ((j == -1) ? 0 : j);
dp[top] = j;
stk[top++] = x;
}
cout << ans << endl;
} #include <stack>
#include<iostream>
typedef long long ll;
using namespace std;
int n, a[100005];
ll ans = 0;
int main() {
int i, j;
cin >> n;
int ans = 0;
for (i = 0; i < n; i++) cin >> a[i];
// 记录一串递增数列,在出现足够小的值时可以用来组成有效序列
stack<pair<int, int>> pre; //记录下前面出现的数字,以及数字出现次数。例如 11 455 1此时就能+2有效序列了。
for (i = 0; i < n; i++) {
while (!pre.empty() && pre.top().first > a[i]) { //如果栈内的值更大,那么需要出栈
ans += pre.top().second;
pre.pop();
}
if (pre.empty()) {
pre.push(make_pair(a[i], 1));
}
else {
if (pre.top().first == a[i]) {
ans += pre.top().second;
pre.top().second++;
if (pre.size() > 1) { //如果pre大于1,那么就意味着左边还有更小的值可以创建有效序列 ,如 1 2 455 2
ans++;
}
}
else {
pre.push(make_pair(a[i], 1));
ans++;
}
}
}
cout << ans;
} #include <bits/stdc++.h>
using namespace std;
int main() {
int n;
long long ans = 0;
cin >> n;
vector<int> st;
vector<int> s;
for(int i = 0; i < n; ++i) {
int num;
cin >> num;
if(!st.empty()) {
int b = 0, e = st.size() - 1;
while(b < e) {
int m = (b + e)/2;
if(s[st[m]] < num) {
b = m + 1;
} else {
e = m;
}
}
while(b > 0 && s[st[b]] >= num) b--;
if(b >= 0) {
ans += st.size() - b;
}
}
while(!st.empty() && s[st.back()] > num) {
st.pop_back();
}
st.push_back(i);
s.push_back(num);
}
cout << ans << endl;
}
// 64 位输出请用 printf("%lld") import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
in.nextLine();
String[] str = in.nextLine().split(" ");
int[] input = new int[n];
for (int i = 0; i < str.length; i++) {
input[i] = Integer.valueOf(str[i]);
}
Deque<int[]> stack = new ArrayDeque<>();
long result = 0;
for (int i = 0; i < input.length; i++) {
int val = input[i];
while (!stack.isEmpty() && val < stack.peekLast()[0]) {
int[] cur = stack.pollLast();
result += cur[1];
}
if (stack.isEmpty()) {
stack.offerLast(new int[]{val, 1});
} else {
int[] cur = stack.peekLast();
if (val == cur[0]) {
result += cur[1];
cur[1]++;
if (stack.size() > 1) {
result++;
}
} else { // if val > cur[0]
result++;
stack.offerLast(new int[]{val, 1});
}
}
}
System.out.println(result);
}
} #include <iostream>
#include <vector>
#include <numeric>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> nums(n, 0);
vector<int> v_stack;
long long ans = 0;
int top = -1;
for (int i = 0; i < n; ++i) {
int x;
cin >> x;
nums[i] = x;
}
int h = 0; //以i为右端点的符合条件子序列数量
for (int i = 0; i < n; ++i) {
if (top >= 0) {
if (nums[v_stack[top]] >= nums[i]) {
while (top >= 0 && nums[v_stack[top]] > nums[i]) {
++h;
v_stack.pop_back();
--top;
}
if (top >= 0) {
++h;
if (nums[v_stack[top]] == nums[i]) {
h += v_stack.size() - 1;
}
}
}
}
v_stack.push_back(i);
++top;
if (i > 0) {
h = h ? h : 1;
ans += h;
}
h = 0;
}
cout << ans << endl;
return 0;
} #include <iostream>
#include <vector>
#include <numeric>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> nums(n, 0);
vector<int> v_stack;
vector<int> dp(n, 0);
long long ans = 0;
int top = -1;
for (int i = 0; i < n; ++i) {
int x;
cin >> x;
nums[i] = x;
}
int h = 0;
for (int i = 0; i < n; ++i) {
if (top >= 0) {
if (nums[v_stack[top]] >= nums[i]) {
while (top >= 0 && nums[v_stack[top]] > nums[i]) {
++h;
v_stack.pop_back();
--top;
}
if (top >= 0) {
if (nums[v_stack[top]] == nums[i]) {
dp[i] = dp[v_stack[top]] + 1;
h += dp[i];
if(top >= dp[i]){
++h;
}
}else{
++h;
}
}
}
}
v_stack.push_back(i);
++top;
if (i > 0) {
h = h ? h : 1;
ans += h;
}
h = 0;
}
cout << ans << endl;
return 0;
} #include<iostream>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
int main()
{
int n;
vector<long> a;
a.clear();
cin >> n;
for(int i = 0; i < n; i++)
{
long val;
cin >> val;
a.push_back(val);
}
// 只有两个元素,统计满足条件的情况
// 所以下面只要考虑三个及三个元素的情况
long count = n - 1;
// 下标入栈
stack<int> s;
for(int j = 0; j < n; j++)
{
long val = a[j];
while(!s.empty() && val < a[s.top()])
{
// 此过程,目的是
// 维持单调栈,入栈的下标所对应的数据一定是单调递增(等于也算)
// 即栈上任意两个下标i,j范围内的任一x下标满足:
// a[x] >= a[i]且a[x] >= a[j] (j > i,i + 1 != j)
// 同时其他元素出栈的时候,符合条件的情况也一并统计
if(s.top() + 1 != j)
count += 1;
// 不符合条件的出栈
s.pop();
}
if(!s.empty())
{
if(s.top() + 1 != j)
// 那么的话,
// 只要是栈上任两个的元素i,j(i + 1 == j)
// 就有s.size()种情况以a[j]为最右侧,且满足条件。
// 如果i + 1 == j,就是只有两个元素的情况,在一开始已经统计,无需重复统计
count += s.size();
else
{
// 特殊情况:
// 栈上的元素对应的数据有可能是一样的
// 这时候,要剔除只有两个元素的情况即可
if(a[s.top()] == val)
count += s.size() -1;
}
}
// j入栈
s.push(j);
}
cout << count << endl;
return 0;
} #include<iostream>
#include<stack>
using namespace std;
int arr[100005];
struct Node{
int value;
int times;
};
long cn2(int x){
return (long)x*(x-1)>>1;
}
int main(){
int n;
long ans=0;
cin>>n;
if(n<2) cout<<0<<endl;
for(int i=0;i<n;i++)cin>>arr[i];
stack<Node> stack;
for(int i = 0; i < n; i++){
while(!stack.empty() && stack.top().value > arr[i]){
Node topNode;
topNode = stack.top();
stack.pop();
ans += topNode.times + cn2(topNode.times);
}
if(!stack.empty() && arr[i] == stack.top().value){
stack.top().times++;
}else{
Node neww;
neww.value=arr[i];
neww.times=1;
stack.push(neww);
}
}
while(!stack.empty()){
ans += cn2(stack.top().times);
stack.pop();
}
for(int i = n - 1; i >= 0; i--){
while(!stack.empty() && stack.top().value > arr[i]){
Node topNode;
topNode = stack.top();
stack.pop();
ans += topNode.times;
}
if(!stack.empty() && arr[i] == stack.top().value){
stack.top().times++;
}else{
Node neww;
neww.value=arr[i];
neww.times=1;
stack.push(neww);
}
}
cout<<ans<<endl;
}