题目描述
战争游戏的至关重要环节就要到来了,这次的结果将决定王国的生死存亡,小B负责首都的防卫工作。首都位于一个四面环山的盆地中,周围的n个小山构成一个环,作为预警措施,小B计划在每个小山上设置一个观察哨,日夜不停的瞭望周围发生的情况。 一旦发生外地入侵事件,山顶上的岗哨将点燃烽烟,若两个岗哨所在的山峰之间没有更高的山峰遮挡且两者之间有相连通路,则岗哨可以观察到另一个山峰上的烽烟是否点燃。由于小山处于环上,任意两个小山之间存在两个不同的连接通路。满足上述不遮挡的条件下,一座山峰上岗哨点燃的烽烟至少可以通过一条通路被另一端观察到。对于任意相邻的岗哨,一端的岗哨一定可以发现一端点燃的烽烟。 小B设计的这种保卫方案的一个重要特性是能够观测到对方烽烟的岗哨对的数量,她希望你能够帮她解决这个问题。
输入描述:
输入中有多组测试数据,每一组测试数据的第一行为一个整数n(3<=n<=10^6),为首都周围的小山数量,第二行为n个整数,依次表示为小山的高度h(1<=h<=10^9).
输出描述:
对每组测试数据,在单独的一行中输出能相互观察到的岗哨的对数。
示例1
输入
5 1 2 4 5 3
输出
7
1 /* 2 * To change this license header, choose License Headers in Project Properties. 3 * To change this template file, choose Tools | Templates 4 * and open the template in the editor. 5 */ 6 package practiceforcompiletest; 7 8 import java.util.Scanner; 9 import java.util.ArrayList; 10 import java.util.Scanner; 11 import java.util.Stack; 12 13 /** 14 * 15 * @author zhangtao 16 */ 17 class Mountain { 18 19 public long val; 20 public long num; 21 22 public Mountain(long v, long n) { 23 this.val = v; 24 this.num = n; 25 } 26 } 27 28 public class PracticeForCompileTest { 29 30 public static void main(String[] args) { 31 Scanner sc = new Scanner(System.in); 32 int n; 33 long count = 0; 34 while (sc.hasNext()) { 35 n = sc.nextInt(); 36 ArrayList<Mountain> mountains = new ArrayList<>(); 37 int maxIndex = 0; 38 int maxHeight = sc.nextInt(); 39 mountains.add(new Mountain(maxHeight, 1)); 40 // 合并相邻相同高度的山,记录最高山的位置 41 for (int i = 1; i < n; i++) { 42 int val = sc.nextInt(); 43 if (val == mountains.get(mountains.size() - 1).val) { 44 mountains.get(mountains.size() - 1).num++; 45 } else { 46 mountains.add(new Mountain(val, 1)); 47 if (val > maxHeight) { 48 maxHeight = val; 49 maxIndex = mountains.size() - 1; 50 } 51 } 52 } 53 // 从最高的山开始,维持单调栈,每次出栈记录符合要求的数量 54 Stack<Mountain> s = new Stack<>(); 55 for (int i = 0; i < mountains.size(); i++) { 56 int index = (i + maxIndex) % mountains.size(); 57 while (!s.isEmpty() && mountains.get(index).val > s.peek().val) { 58 Mountain m = s.pop(); 59 // 出栈山顶与左边以及登高的山峰联通数 60 count += m.num + m.num * (m.num - 1) / 2; 61 if (!s.isEmpty()) { 62 // 出栈山顶与右边的山顶连通数 63 count += m.num; 64 } 65 } 66 if (s.isEmpty() || mountains.get(index).val < s.peek().val) { 67 s.push(mountains.get(index)); 68 } else { 69 s.peek().num += mountains.get(index).num; 70 } 71 } 72 // 栈中剩余的山出栈 73 while (!s.isEmpty()) { 74 Mountain m = s.pop(); 75 if (s.size() == 1 && s.peek().num == 1) { 76 count += m.num + m.num * (m.num - 1) / 2; 77 } else if (s.size() < 1) { 78 count += m.num * (m.num - 1) / 2; 79 } 80 // 只能和左右两边相联通 81 else { 82 count += m.num + (m.num + m.num * (m.num - 1) / 2); 83 } 84 } 85 System.out.println(count); 86 } 87 } 88 }