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\n", 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 
*/
posted @ 2021-07-08 14:26  这知识他不进我的脑子  阅读(68)  评论(0)    收藏  举报