好题
题意:有一座座山围成一圈,有各自的高度,当两座山之间没有比它们更高的山时认为这两座山彼此可见,求共有多少组山彼此可见。
题解:显然,暴力可做,但是超时。
先把环拆成链,方便处理。
找最高的一座山作为链头(如果不唯一,任选一个),从这座山开始,逐个把右边的山加入进来,直至所有山都遍历结束。然后再把链的尾端加入最高的山,初始化完毕。
定义三个数组
L[i]表示i左侧第一个比 i 高的位置。
R[i]表示i右侧第一个比 i 高的位置。
C[i]表示从i到 R[i]的左开右闭区间内高度等于i的山的数目。
所有C[i]都是答案,如果不是最高的山,(i,L[i]),(i,R[i])也是答案,不过如果L[i] == 0 && R[i] == n 时这两个指的是同一座山,即最高的山。
这个答案的计算方法不太好想,因为它并不是顺序这来统计的,但它确实做到了一个不重,一个不漏。试着解释一下吧
高度相同的且之间没有更高的山的被C[i]统计。其余的,举个栗子, 9 7 5 9 这个链, (7,5)不是通过7计算得到的,而是通过5,通过(5,L[5])
#include <bits/stdc++.h>
long long h[1000001], hh[1000001], c[1000001], r[1000001],l [1000001];
int main(){
long long n, maxx, maxi, ans;
scanf("%lld", &n);
for(long long i = 0; i < n; i ++)
scanf("%lld", &h[i]);
maxi = 0;
maxx = h[0];
for(long long i = 1; i < n; i ++)
if(h[i] > maxx){
maxx = h[i];
maxi = i;
}
for(long long i = 0; i < n; i ++)
hh[i] = h[(maxi + i) % n];
hh[n] = hh[0];
c[n] = 0;
for(long long i = n - 1; i >= 0; i --){
r[i] = i + 1;
while(r[i] < n && hh[i] > hh[r[i]])
r[i] = r[r[i]];
if(r[i] < n && hh[i] == hh[r[i]]){
c[i] = c[r[i]] + 1;
r[i] = r[r[i]];
}
}
l[0] = 0;
for(long long i = 1; i <= n; i ++){
l[i] = i - 1;
while(l[i] > 0 && hh[i] >= hh[l[i]])
l[i] = l[l[i]];
}
ans = 0;
for(long long i = 0; i < n; i ++){
ans += c[i];
if(hh[i] < hh[0]){
if(l[i] == 0 && r[i] == n)
ans ++;
else
ans += 2;
}
}
printf("%lld\n", ans);
return 0;
}