• CF-5E.Bindian Signalizing(单调栈)


    思路
    对于每一对答案贡献((i,j)),假定(a[i] leq a[j]),那么我们考虑枚举每一位(i)去计算其贡献。
    对于每一个(i),令(l[i])为左边第一个大于(a[i])的下标,(r[i])为右边第一个大于(a[i])的下标,(cnt[i])表示从(a[j]=a[i](i+1 leq j leq r[i]))的个数。
    既然每一个数都要考虑左边比他的,右边比他的情况。考虑把环拆成链可以拆成第一个数是最大值的情况,那么设置边界(n+1)个数也是最大值的情况即可。
    维护(l[i],r[i],cnt[i])的一个过程用单调栈维护即可。
    然后对于每一个下标(i),其都有一个贡献值(cnt[i]),若(a[i])不是最大值,那么其对答案的贡献+2,如果发现他的(r[i])(l[i])表示的是同一个位置即(l[i]=1,r[i]=n+1),那么说明有重复的,需要-1.
    最后考虑最大值即可,若最大值有x个,那么贡献就是(C_{x}^{2})
    代码

    /*人一我百,人十我万*/
    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    #define int LL
    typedef pair<int, LL> PIL;
    typedef pair<int, int> PII;
    typedef pair<int, double> PID;
    typedef unsigned long long ULL;
    #define x first
    #define y second
    const int N = 2e6 + 10, M = 1e5 + 10;
    const double PI = acos(-1.0);
    const double eps = 1e-5;
    const int mod = 1000000007;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    #define gcd __gcd
    
    int a[N], l[N], r[N], b[N];
    LL cnt[N];
    stack<int> s;
    
    void solve() {
        int n;
        scanf("%lld", &n);
        int mx = 0, pos = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
            if(mx < a[i]) {
                mx = a[i];
                pos = i;
            }
        }
        for(int i = 1; i <= n; i++) {
            b[i] = a[pos++];
            if(pos > n) pos = 1;
        }
        b[++n] = mx;
    
        int sum = 0;
        for(int i = 1; i <= n; i++) {
            while(!s.empty() && b[s.top()] <= b[i]) s.pop();
            if(!s.empty()) l[i] = s.top();
            s.push(i);
        }
        while(!s.empty()) s.pop();
        for(int i = n; i >= 1; i--) {
            while(!s.empty() && b[s.top()] <= b[i]) {
                if(b[s.top()] == b[i] && i <= n && b[s.top()] != mx) cnt[i] = cnt[s.top()] + 1;
                s.pop();
            }
            if(!s.empty()) r[i] = s.top();
            s.push(i);
        }
        LL res = 0;
        for(int i = 1; i < n; i++) {
            res += cnt[i];
            if(b[i] < b[1]) {
                res += 2;
                if(l[i] == 1 && r[i] == n) res--;
            }
        }
        for(int i = 1; i < n; i++) {
            if(mx == a[i]) sum++;
        }
        res += 1LL * sum * (sum - 1) / 2;
        printf("%lld
    ", res);
    }
    
    signed main() {
        #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        #endif // ONLINE_JUDGE
    
        // int t; cin >> t; while(t--)
        solve();
        return 0;
    }
    
    /*
    10
    7 3 6 8 1 7 8 4 9 7 
    */
    
  • 相关阅读:
    Linux curl使用简单介绍
    SecureCRT编码转换vim
    BigTable/HBase基本概念解读 & Hbase shell常用命令
    Crontab用法说明(Linux)
    Sina SSO 登陆过程分析
    浅谈队列
    搞怪的 log4net 记录日志 性能测试
    iBatis.Net异步多线程 操作Ibatis报错
    高并发高负载的大型网站系统架构
    [置顶] IIs Web 站点安全 监控 站点自动部署 重启
  • 原文地址:https://www.cnblogs.com/ZX-GO/p/14985923.html
Copyright © 2020-2023  润新知