cf5 E. Bindian Signalizing

题意:

给定长为 \(n\) 的环,对环上两点 \(i,j\),若存在 \(i\)\(j\) 的弧,弧中的数均不大于 \(a_i\)\(a_j\),则称 \(i\)\(j\) 可以互相看到。求可以互相看到的位置对数。

思路:

拆环成链,把最大的数 \(mx\) 放在链头(可能不止一个最大的,但没关系)

在链尾也插一个 \(mx\)

对环中的位置 \(i\),求左边最近的大于 \(a_i\) 的位置 \(left_i\) 和右边最近的大于 \(a_i\) 的位置 \(right_i\),则有两对 \(<left_i,i>\)\(<i,right_i>\)。另外 \((left_i,right_i)\) 中所有与 \(i\) 相等的位置 \(p\) 也会与 \(i\) 配对,为了避免重复计数我们统计 \((left_i,i-1)\)\(p\) 的数量,记为 \(same_i\)

void sol() {
    int n; cin >> n;
    vector<int> a(n); for(int &x : a) cin >> x;
    
    rotate(a.begin(), max_element(a.begin(),a.end()), a.end());
    
    a.push_back(a[0]);
    
    vector<int> lef(n), rig(n), same(n);
    
    stack<int> stk;
    for(int i = 0; i < n; i++) {
        while(stk.size() && a[stk.top()] <= a[i]) {
            if(a[stk.top()] == a[i]) same[i] = same[stk.top()] + 1;
            stk.pop();
        }
        lef[i] = stk.size() ? stk.top() : -1;
        stk.push(i);
    }
    stack<int>().swap(stk); //清空
    stk.push(n);
    for(int i = n-1; i >= 0; i--) {
        while(stk.size() && a[stk.top()] <= a[i]) stk.pop();
        rig[i] = stk.size() ? stk.top() : -1;
        stk.push(i);
    }
    
    ll ans = 0; for(int i = 1; i < n; i++)
        ans += (lef[i] != -1) + (rig[i] != -1)
            - (lef[i] == 0 && rig[i] == n) + same[i]; //注意0与n是同一个位置
    cout << ans << '\n';
}
posted @ 2022-09-16 18:05  Bellala  阅读(42)  评论(0)    收藏  举报