链接: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 ",it->first,tt/gg,x/gg); } } }