Nowcoder9982A.牛牛和牛妹的RMQ(线段树+单调栈)

链接:https://ac.nowcoder.com/acm/contest/9982/A
来源:牛客网

某天,牛妹来找牛牛学习RMQ算法(Range Minimum/Maximum Query),即区间最值查询。也就是给定一个数组区间[L,R],查询该子区间的最大值。
假设子数组的两端点下标分别为L,R的话RMQ(L,R)就表示数组区间[L,R]的最大值。
因为牛妹学会了RMQ算法,所以牛牛准备和她玩个游戏验证她真的学会了。

牛牛有一个长度大小为n的全排列数组,即数组中的数字是1~n,且每个数字仅出现1次。
她们一共玩了m轮游戏,在每轮游戏中,牛牛都准备了k个不同的下标。
然后牛牛和牛妹各自随机选出一个下标,并且两人所选下标可以是相同的。
假设牛牛选出的下标为a,牛妹选出的下标为b的话,那么本轮游戏的得分就是RMQ(min(a,b),max(a,b))。

请你告诉牛牛,对于每轮游戏可能的得分都有哪几种情况,以及这些情况出现的概率各是多大?

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
int n,m;
int a[maxn],p[maxn];
struct node {
    int l,r,sum;
}segTree[maxn<<2];
void build (int i,int l,int r) {
    segTree[i].l=l;
    segTree[i].r=r;
    if (l==r) {
        segTree[i].sum=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    segTree[i].sum=max(segTree[i<<1].sum,segTree[i<<1|1].sum);
}
int query (int i,int l,int r) {
    if (segTree[i].l>=l&&segTree[i].r<=r) return segTree[i].sum;
    int mid=(segTree[i].l+segTree[i].r)>>1;
    int ans=0;
    if (l<=mid) ans=max(ans,query(i<<1,l,r));
    if (r>mid) ans=max(ans,query(i<<1|1,l,r));
    return ans;
}
int pp[maxn],L[maxn],R[maxn];
int main () {
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",a+i);
    build(1,1,n);
    scanf("%d",&m);
    while (m--) {
        int k;
        scanf("%d",&k);
        for (int i=1;i<=k;i++) scanf("%d",p+i);
        sort(p+1,p+k+1);
        map<int,long long> mp;
        for (int i=1;i<k;i++) {
            int x=query(1,p[i],p[i+1]);
            pp[i]=x;
        }
        stack<int> st;
        for (int i=1;i<k;i++) R[i]=k,L[i]=0;
        for (int i=1;i<k;i++) {
            while (st.size()) {
                int u=st.top();
                if (pp[u]<=pp[i])
                    st.pop();
                else {
                    L[i]=u;
                    break;
                }
            }
            st.push(i);
        }
        while (st.size()) st.pop();
        for (int i=k-1;i>=1;i--) {
            while (st.size()) {
                int u=st.top();
                if (pp[u]<=pp[i])
                    st.pop();
                else {
                    R[i]=u;
                    break;
                }
            }
            st.push(i);
        }
        for (int i=1;i<k;i++) {
            int j;
            for (j=i;j<k;j++) if (pp[i]!=pp[j]) break;
            mp[pp[i]]+=2ll*(i-L[i]-1)*(R[j-1]-j);
            mp[pp[i]]+=1ll*(j-i+1)*(j-i);
            mp[pp[i]]+=2ll*(j-i)*(i-L[i]-1);
            mp[pp[i]]+=2ll*(j-i)*(R[j-1]-j);
            i=j-1; 
        }
        for (int i=1;i<=k;i++) mp[a[p[i]]]++;
        for (auto it=mp.begin();it!=mp.end();it++) {
            long long tt=it->second;
            long long x=1ll*k*k;
            long long gg=__gcd(tt,x);
            printf("%d %lld/%lld\n",it->first,tt/gg,x/gg);
        }
    }
}

 

posted @ 2021-02-03 20:07  zlc0405  阅读(297)  评论(0编辑  收藏  举报