第一行输入一个整数 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]
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);
}
} 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;
}
}