import java.util.Scanner; import java.util.Stack; /** * JD6 保卫方案 * @author d3y1 */ public class Main { private static int N; public static void main(String[] args) { Scanner in = new Scanner(System.in); while(in.hasNext()){ solution(in); } } /** * 单调栈 * @param in */ private static void solution(Scanner in){ N = in.nextInt(); // 山峰高度数组 int[] heights = new int[N]; for (int i=0; i<N; i++) { heights[i] = in.nextInt(); } long result = getVisiblePairs(heights); System.out.println(result); } /** * 获取可互见对数: 相邻无重复高度 * @param heights * @return */ public static int getVisiblePairsNoRepeat(int[] heights){ if (heights == null || N < 2){ return 0; } // 除去最高的两座山峰 每一座山峰都可以看见相邻2座山峰 2*(N-2) // 最高的两座山峰之间是1对 // 2*(N-2)+1 = 2*N-3 return (N*2-3); } /** * 获取可互见对数: 相邻有重复高度 * @param heights * @return */ public static long getVisiblePairs(int[] heights){ if (N < 2){ return 0; } // 找到最高山峰索引 从该索引开始遍历 int maxHeightIndex = 0; for (int i=0,size=N; i<size; i++) { maxHeightIndex = heights[maxHeightIndex]>heights[i] ? maxHeightIndex:i; } // 单调栈 栈底到栈顶递减 Stack<Mountain> stack = new Stack<>(); stack.push(new Mountain(maxHeightIndex,1)); // 获得最高山峰的下一个索引 int next = getNextIndex(maxHeightIndex); long count = 0; Mountain curr; while (next != maxHeightIndex){ // 单调栈循环 // 当加入的山峰高度会破坏栈的单调性时 弹出栈顶元素 while (!stack.isEmpty() && heights[stack.peek().index]<heights[next]){ curr = stack.pop(); // 往上配对数 + 当前相同高度配对数 count += curr.num + getCurrHeightPairs(curr.num); if(!stack.isEmpty()){ // 往下配对数 count += curr.num; } } if(!stack.isEmpty() && heights[stack.peek().index]==heights[next]){ // 山峰高度相同 则增加栈顶元素的num值 stack.peek().num++; }else{ // 此时加入的山峰不会对栈的单调性造成影响 直接入栈 stack.push(new Mountain(next,1)); } // 继续向后遍历 next = getNextIndex(next); } // 遍历完成后 将栈中剩余元素进行处理 可能依次经历3种阶段 // 阶段1 栈中剩余元素>2 while (stack.size() > 2){ curr = stack.pop(); // 环形 栈底元素也可看到当前元素(也可配对) // 往下配对数 + 栈底配对数 + 当前相同高度配对数 count += 2*curr.num + getCurrHeightPairs(curr.num); } // 阶段2 栈中剩余元素=2 if (stack.size() == 2){ curr = stack.pop(); // 当前相同高度配对数 + 往下配对数 + 栈底配对数(栈底元素数量>1) count += getCurrHeightPairs(curr.num) + (stack.peek().num==1 ? curr.num : 2*curr.num); } // 阶段3 栈中剩余元素=1 if (stack.size() == 1){ curr = stack.pop(); count += getCurrHeightPairs(curr.num); } return count; } /** * 获取当前索引的下一个索引 * @param index * @return */ public static int getNextIndex(int index){ return (index+1)%N; } /** * 当前相同高度山峰配对数 * @param num * @return */ public static long getCurrHeightPairs(long num){ return num*(num-1)/2; } static class Mountain{ // 山峰高度数组 索引 public int index; // 相同高度山峰个数(相邻) public int num; public Mountain(int index,int num){ this.index = index; this.num = num; } } }