牛牛与牛妹的RMQ

题目链接:https://ac.nowcoder.com/acm/problem/217803

思路:首先考虑如何求出所有的得分情况,可以发现每个p[i]对应的a[p[i]] 是肯定会出现的

而将p[i] 排序后 每段p[i] p[i+1] 中的最大值也是会出现的, 其他都不会出现, 那么这里就考虑用RMQ或者线段树求一下区间的最大值

然后考虑如何计算得分概率,对应每一个数 可以预处理他左边能达到的地方和右边能达到的最远的地方,记作l[i] r[i] 

用单调栈可以o n 处理出来  然后剩下的就是维护 每次查询的时候  左边和右边都有多少个可选的 相乘*2 ,如果自己本身的位置也可选就减1

最后在gcd 化简分数即可

牛牛与牛妹的RMQ
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int maxn=1e5+10;
  4 const int mod=998244353;
  5 #define ll long long
  6 #define pi pair<ll,ll>
  7 #define fi first
  8 #define sc second
  9 #define pb push_back
 10 int a[maxn],pos[maxn],p[maxn];
 11 int n,m,k;
 12 int l[maxn],r[maxn];
 13 int tr[maxn];
 14 pi b[maxn];
 15 
 16 ll gcd(ll a,ll b)
 17 {
 18     if(b==0) return a;
 19     return gcd(b,a%b);
 20 }
 21 
 22 void add(int x,int v)
 23 {
 24     while(x<=n) tr[x]+=v,x+=x&-x;
 25 }
 26 int query(int x)
 27 {
 28     int ans=0;
 29     while(x) ans+=tr[x],x-=x&-x;
 30     return ans;
 31 }
 32 
 33 struct ac
 34 {
 35     int l,r,mx;
 36 };
 37 ac tree[maxn*4];
 38 void pushup(int x)
 39 {
 40     tree[x].mx=max(tree[x<<1].mx,tree[x<<1|1].mx);
 41 }
 42 void build(int x,int l,int r)
 43 {
 44     tree[x]={l,r};
 45     if(l==r)
 46     {
 47         tree[x].mx=a[l];
 48         return;
 49     }
 50     int mid=(l+r)/2;
 51     build(x<<1,l,mid);
 52     build(x<<1|1,mid+1,r);
 53     pushup(x);
 54 }
 55 int querymx(int x,int l,int r)
 56 {
 57     if(l>r) return 0;
 58     int L=tree[x].l,R=tree[x].r;
 59     if(l<=L&&R<=r) return tree[x].mx;
 60     int mid=(L+R)/2;
 61     int ans=0;
 62     if(l<=mid) ans=querymx(x<<1,l,r);
 63     if(r>mid) ans=max(ans,querymx(x<<1|1,l,r));
 64     return ans;
 65 }
 66 
 67 
 68 
 69 
 70 int main()
 71 {
 72     ios::sync_with_stdio(0);
 73     cin.tie(0);
 74     cin>>n;
 75     for(int i=1;i<=n;i++) cin>>a[i],pos[a[i]]=i;
 76     stack<int>s;
 77     for(int i=1;i<=n;i++)
 78     {
 79         int x=a[i];
 80         while(!s.empty()&&x>a[s.top()]) s.pop();
 81         if(s.empty()) l[i]=1;
 82         else l[i]=s.top()+1;
 83         s.push(i);
 84     }
 85     while(!s.empty()) s.pop();
 86     for(int i=n;i>=1;i--)
 87     {
 88         int x=a[i];
 89         while(!s.empty()&&x>a[s.top()]) s.pop();
 90         if(s.empty()) r[i]=n;
 91         else r[i]=s.top()-1;
 92         s.push(i);
 93     }
 94     build(1,1,n);
 95     cin>>m;
 96     while(m--)
 97     {
 98         int k;
 99         cin>>k;
100         for(int i=1;i<=k;i++) cin>>p[i];
101         sort(p+1,p+1+k);
102         vector<int>cnt;
103         for(int i=1;i<=k;i++)
104         {
105             int x=a[p[i]],y=querymx(1,p[i],p[i+1]);
106             if(i!=k) cnt.pb(y);
107             cnt.pb(x);
108         }
109         sort(cnt.begin(),cnt.end());
110         cnt.erase(unique(cnt.begin(),cnt.end()),cnt.end());
111         for(int i=1;i<=k;i++) add(p[i],1);
112         int tot=0;
113 
114         for(auto &v:cnt)
115         {
116             ll mu=1ll*k*k;
117             int pp=pos[v];
118             ll L=query(pp)-query(l[pp]-1);
119             ll R=query(r[pp])-query(pp-1);
120             ll zi=L*R*2;
121             if(query(pp)-query(pp-1)) zi--;
122             ll d=gcd(zi,mu);
123             zi/=d,mu/=d;
124             b[++tot]={zi,mu};
125         }
126         for(int i=1;i<=tot;i++)
127         {
128             cout<<cnt[i-1]<<" "<<b[i].fi<<"/"<<b[i].sc<<'\n';
129         }
130 
131         for(int i=1;i<=k;i++) add(p[i],-1);
132 
133     }
134 
135 
136 
137 
138 
139 
140 
141 
142 
143 }
View Code

 

上一篇:力扣(LeetCode)算法_C++——用两个栈实现队列


下一篇:创建一个项目