<span>模拟104 题解</span>

A. 中间值

二分答案在数组$a$中的排名,则得到期望的在数组$b$中的排名。

当数组$b$中对应的数恰好是大于二分值的第一个数,代表二分到了答案。

通过对应的数与当前数的大小关系,可以确定二分方向。

同理还应当二分答案在数组$b$中的排名。

然而这个做法实现比较困难,还有另一个更帅的二分做法。

考虑当前的问题:

数组$a$,单调区间$[l_1,r_1]$,数组$b$,单调区间$[l_2,r_2]$,查询共同区间的第$k$大值。

不妨将$k$折半,分别对应在$a$,$b$数组中,

可以得到$a_{r_1-\frac{k}{2}}$,$b_{r_2-\frac{k}{2}}$。

将二者比较可以确定一段无用的区间。

设$a_{r_1-\frac{k}{2}}<b_{r_2-\frac{k}{2}}$,$b$数组在大于$r_2-\frac{k}{2}$的部分只会更大。

所以问题的规模降低了一半,变为了问题

数组$a$,单调区间$[l_1,r_1]$,数组$b$,单调区间$[l_2,r_2-\frac{k}{2}]$,查询共同区间的第$\frac{k}{2}$大值。

所以可以$O(logn)$处理每组询问。

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 const int N=5e5+7;
 5 const int inf=0x3f3f3f3f;
 6 int n,m;
 7 int a[N],b[N];
 8 inline int query(int l1,int r1,int l2,int r2){
 9     int l,r,lst,nxt,ans=-1,len1=r1-l1+1,len2=r2-l2+1,aim=len1+len2+1>>1;
10     lst=b[l2-1]; nxt=b[r2+1];
11     b[l2-1]=-1; b[r2+1]=inf;
12     l=l1; r=r1;
13     while(l<=r){
14         int mid=l+r>>1,rk=mid-l1+1,to=aim-rk+l2;//大于 的第一个
15         if(to<l2){
16             r=mid-1;
17             continue;
18         }
19         if(to>r2+1){
20             l=mid+1;
21             continue;
22         }
23         if(b[to]>=a[mid]&&b[to-1]<=a[mid]){
24             ans=a[mid];
25             break;
26         }
27         if(l==r) break;
28         if(b[to-1]>a[mid]) l=mid+1;
29         else r=mid-1;
30     }
31     b[l2-1]=lst; b[r2+1]=nxt;
32     if(~ans) return ans;
33     lst=a[l1-1]; nxt=a[r1+1];
34     a[l1-1]=-1; a[r1+1]=inf;
35     l=l2; r=r2;
36     while(l<=r){
37         int mid=l+r>>1,rk=mid-l2+1,to=aim-rk+l1;
38         if(to<l1){
39             r=mid-1;
40             continue;
41         }
42         if(to>r1+1){
43             l=mid+1;
44             continue;
45         }
46         if(a[to]>=b[mid]&&a[to-1]<=b[mid]){
47             ans=b[mid];
48             break;
49         }
50         if(a[to-1]>b[mid]) l=mid+1;
51         else r=mid-1;
52     }
53     a[l1-1]=lst; a[r1+1]=nxt;
54     if(~ans) return ans;
55     return 0;
56 }
57 inline int read(register int x=0,register char ch=getchar(),register char f=0){
58     for(;!isdigit(ch);ch=getchar()) f=ch=='-';
59     for(; isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
60     return f?-x:x;
61 }
62 int main(){
63     freopen("median.in","r",stdin);
64     freopen("median.out","w",stdout);
65     n=read(); m=read(); a[0]=b[0]=-1; a[n+1]=b[n+1]=inf;
66     for(int i=1;i<=n;++i) a[i]=read();
67     for(int i=1;i<=n;++i) b[i]=read();
68     for(int i=1,opt,l1,r1,l2,r2;i<=m;++i){
69         opt=read();
70         if(opt==1){
71             l1=read(); r1=read(); l2=read();
72             if(l1==0) a[r1]=l2;
73             else b[r1]=l2;
74         }
75         else{
76             l1=read(); r1=read(); l2=read(); r2=read();
77             printf("%d\n",query(l1,r1,l2,r2));
78         }
79     }
80     return 0;
81 }
解法一
 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 const int N=5e5+7;
 5 const int inf=0x3f3f3f3f;
 6 int n,m;
 7 int a[N],b[N];
 8 int solve(int st1,int ed1,int st2,int ed2,int k){
 9     if(k==1){
10         if(st1<=ed1&&st2<=ed2) return max(a[ed1],b[ed2]);
11         return st1<=ed1?a[ed1]:b[ed2];
12     }
13     int x=k>>1,y=k-x,to1=ed1-x,to2=ed2-y;
14     if(to1<st1-1) return solve(st1,ed1,st2,to2,k-y);
15     if(to2<st2-1) return solve(st1,to1,st2,ed2,k-x);
16     if(a[to1+1]>=b[to2+1]) return solve(st1,to1,st2,ed2,k-x);
17     return solve(st1,ed1,st2,to2,k-y);
18 }
19 inline int read(register int x=0,register char ch=getchar(),register char f=0){
20     for(;!isdigit(ch);ch=getchar()) f=ch=='-';
21     for(; isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
22     return f?-x:x;
23 }
24 int main(){
25     freopen("median.in","r",stdin);
26     freopen("median.out","w",stdout);
27     n=read(); m=read();
28     for(int i=1;i<=n;++i) a[i]=read();
29     for(int i=1;i<=n;++i) b[i]=read();
30     for(int i=1,opt,l1,r1,l2,r2;i<=m;++i){
31         opt=read();
32         if(opt==1){
33             l1=read(); r1=read(); l2=read();
34             if(l1==0) a[r1]=l2;
35             else b[r1]=l2;
36         }
37         else{
38             l1=read(); r1=read(); l2=read(); r2=read();
39             printf("%d\n",solve(l1,r1,l2,r2,r2+r1-l1-l2+3>>1));
40         }
41     }
42     return 0;
43 }
解法二

 

 

 

B. 最小值

首先写出弱智$dp$。

$dp_i$表示以$i$为结尾的几段区间的最优决策下的答案。

$dp_i=dp_{j-1}+f(min_{k=j}^i a_k)$。

这个东西只与两点间的最值有关,所以单调栈维护最值的决策区间,

顺便线段树维护一下$dp$的最优决策就完了。

 

 

 

C. 最大值

首先是一个整数期望公式。

$x$为一个随机变量,那么

$E(x)=\sum \limits_{i=1}^{\inf}P(x==i)*i$

$E(x)=\sum \limits_{i=1}^{\inf}P(x==i)\sum \limits_{j=1}^{i}$

改变枚举顺序,有

$E(x)=\sum \limits_{i=1}^{\inf}P(x>=i)$

应当注意到,本题中每组询问是独立互不影响的,

也就是说可以分别统计每组询问的答案,之后简单求和。

求单组询问的期望,枚举$i$,问题是求$P(max_{j=l}^{r}v_j)>=i)$

$=1-\Pi_{j=l}^{r}P(v_j<x)$

$=1-\Pi_{j=l}^{r}1-P(v_j>=x)$

对于一个点,$P(v_j>=x)$是容易求出的。

题中的特殊性质是,不存在区间包含的情况,

所以对所有区间按左端点排序,包含一个点的区间是连续的。

对于相邻两个$x$,可以将答案简单的除原概率,乘上新的概率。

注意到本题中的$P(v_j>=x)$是单调的,只要倒序枚举$x$,就可以有效避免除$0$的情况。

对所有的询问建树,问题转化为区间乘法(当然还有通过乘逆元进行的除法),顺便维护整体的和就可以了。

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<vector>
  6 #define lch p<<1
  7 #define rch p<<1|1
  8 #define ll long long
  9 using namespace std;
 10 const int mod=1e9+7;
 11 const int N=2e5+7;
 12 int n,m,q,cnt;
 13 int lsh[N],L[N],R[N];
 14 vector<pair<int,ll> > ve[N],f[N];
 15 inline int read(register int x=0,register char ch=getchar(),register char f=0){
 16     for(;!isdigit(ch);ch=getchar()) f=ch=='-';
 17     for(; isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
 18     return f?-x:x;
 19 }
 20 inline ll qpow(ll x,int k,ll r=1){
 21     for(;k;k>>=1,x=x*x%mod) if(k&1) r=r*x%mod;
 22     return r;
 23 }
 24 struct Query{
 25     int l,r;
 26 }que[N];
 27 struct node{
 28     int l,r;
 29     ll val,lzy;
 30 }s[N<<2];
 31 void build(int p,int l,int r){
 32     s[p].l=l; s[p].r=r; s[p].lzy=1; s[p].val=r-l+1;
 33     if(l==r) return ;
 34     int mid=l+r>>1;
 35     build(lch,l,mid);
 36     build(rch,mid+1,r);
 37 }
 38 inline void down(int p){
 39     s[lch].val=s[p].lzy*s[lch].val%mod;
 40     s[rch].val=s[p].lzy*s[rch].val%mod;
 41     s[lch].lzy=s[p].lzy*s[lch].lzy%mod;
 42     s[rch].lzy=s[p].lzy*s[rch].lzy%mod;
 43     s[p].lzy=1;
 44 }
 45 void mult(int p,int l,int r,ll val){
 46     if(s[p].l>=l&&s[p].r<=r) return s[p].val=s[p].val*val%mod,s[p].lzy=s[p].lzy*val%mod,void();
 47     if(s[p].lzy!=1) down(p);
 48     if(l<=s[lch].r) mult(lch,l,r,val);
 49     if(r>=s[rch].l) mult(rch,l,r,val);
 50     s[p].val=(s[lch].val+s[rch].val)%mod;
 51 }
 52 int main(){
 53     freopen("max.in","r",stdin);
 54     freopen("max.out","w",stdout);
 55     n=read(); m=read(); q=read();
 56     for(int i=1,x,y,p;i<=m;++i){
 57         x=read(); y=read(); p=read(); lsh[++cnt]=y;
 58         ve[x].push_back(make_pair(y,p));
 59     }
 60     sort(lsh+1,lsh+cnt+1); cnt=unique(lsh+1,lsh+cnt+1)-lsh-1;
 61     for(int i=1;i<=n;++i){
 62         sort(ve[i].begin(),ve[i].end());
 63         for(int j=0;j<ve[i].size();++j) ve[i][j].first=lower_bound(lsh+1,lsh+cnt+1,ve[i][j].first)-lsh;
 64         for(int j=0;j<ve[i].size();++j){
 65             if(f[i].empty()||ve[i][j].first!=f[i].back().first) f[i].push_back(ve[i][j]);
 66             else f[i].back().second=((1-(1-f[i].back().second)*(1-ve[i][j].second))%mod+mod)%mod;
 67         }
 68         ve[i].clear();
 69         ll p=1,po=0;//前面一个都没出现的概率
 70         for(int j=0;j<f[i].size();++j){
 71             ll tmp=f[i][j].second;
 72             f[i][j].second=p*f[i][j].second%mod;
 73             p=p*(1-tmp+mod)%mod;
 74             po=(po+f[i][j].second)%mod;
 75         }
 76         f[i].push_back(make_pair(0,1-po+mod));
 77         sort(f[i].begin(),f[i].end());
 78         for(int j=f[i].size()-2;~j;--j) (f[i][j].second+=f[i][j+1].second)%=mod;
 79     }
 80     for(int i=1;i<=n;++i) for(int j=0;j<f[i].size();++j) ve[f[i][j].first].push_back(make_pair(i,j));
 81     for(int i=1;i<=n;++i) f[i].push_back(make_pair(cnt+1,0));
 82     ll ans=0;
 83     for(int i=1;i<=q;++i) que[i].l=read(),que[i].r=read();
 84     sort(que+1,que+q+1,[](const Query &x,const Query &y){return x.l<y.l;});
 85     L[0]=1; R[n+1]=q;
 86     for(int i=1;i<=n;++i){
 87         L[i]=L[i-1];
 88         while(L[i]<=q&&que[L[i]].r<i) ++L[i];
 89     }
 90     for(int i=n;i;--i){
 91         R[i]=R[i+1];
 92         while(R[i]&&que[R[i]].l>i) --R[i];
 93     }
 94     build(1,1,q);
 95     for(int i=cnt;i;--i){
 96         for(int j=0;j<ve[i].size();++j){
 97             int pos=ve[i][j].first;
 98             if(L[pos]>R[pos]) continue;
 99             mult(1,L[pos],R[pos],qpow(1-f[pos][ve[i][j].second+1].second+mod,mod-2));
100             mult(1,L[pos],R[pos],1-f[pos][ve[i][j].second].second);
101         }
102         (ans+=(lsh[i]-lsh[i-1])*(q-s[1].val)%mod)%=mod;
103     }
104     printf("%lld\n",(ans+mod)%mod);
105     return 0;    
106 }
T3
全部评论

相关推荐

11-01 20:03
已编辑
门头沟学院 算法工程师
Amazarashi66:这种也是幸存者偏差了,拿不到这个价的才是大多数
点赞 评论 收藏
分享
11-09 17:30
门头沟学院 Java
TYUT太摆金星:我也是,好几个华为的社招找我了
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务