codeforces 5e dp

好题

题意:有一座座山围成一圈,有各自的高度,当两座山之间没有比它们更高的山时认为这两座山彼此可见,求共有多少组山彼此可见。

题解:显然,暴力可做,但是超时。

先把环拆成链,方便处理。

找最高的一座山作为链头(如果不唯一,任选一个),从这座山开始,逐个把右边的山加入进来,直至所有山都遍历结束。然后再把链的尾端加入最高的山,初始化完毕。

定义三个数组

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;
}

猜你喜欢

转载自blog.csdn.net/qq_38759433/article/details/86514227