cf5 E. Bindian Signalizing

题意:

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

思路:

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

在链尾也插一个 mx

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

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 @   Bellala  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示