AT_abc331_e [ABC331E] Set Meal 题解
题意
给定$L$个二元组$(c_i,d_i)$,再从$n$个数字$a_i$和$m$个数字$b_i$各选取一个数组成一个二元组$(a_i,b_j)$,使得二数之和最大并且满足$(i,j)$不是$L$个元组的子集。
数据范围
- $ 1\ \leq\ N,\ M\ \leq\ 10^5 $
- $ 0\ \leq\ L\ \leq\ \min(10^5,\ N\ M\ -\ 1) $
思路
先考虑没有$L$个二元组限制时我们是如何处理的,显然,先把求出$b$数组中的最大值再在$a$数组枚举答案。时间复杂度为$O(n)$。
现在考虑有条件限制的情况,很容易发现对于一个$i$,把它不能与它配对的$j$排序后的数组为$g$,那么对于所有$x$都可以在$g[k]+1 \sim\ g[k+1]-1$内与$i$配对。根据最优性,我们需要在这个区间内以$O(logn)$的时间复杂度求出最大值,此时就可用$ST$表或者线段树维护。时间复杂度$O(mlogm+nlogn)$。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+50;
int f[N][19],a[N],b[N],n,m,l,ans,LG[N];
vector<int> g[N];
void st_prework(){
for(int j=1;j<=log2(m);j++){
for(int i=1;i+(1<<j)-1<=m;i++){
f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]);
}
}
return;
}
int query(int l,int r){
if(r<l)return 0;
int k=log2(r-l+1);
return max(f[l][k],f[r-(1<<k)+1][k]);
}
signed main(){
scanf("%lld %lld %lld",&n,&m,&l);
LG[0]=-1;
for(int i=1;i<=max(n,m);i++)LG[i]=LG[i>>1]+1;
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1;i<=m;i++){
scanf("%lld",&b[i]);
f[i][0]=b[i];
}
for(int i=1;i<=l;i++){
int x,y;
scanf("%lld %lld",&x,&y);
g[x].push_back(y);
}
st_prework();
for(int i=1;i<=n;i++){
int res=0;
if(g[i].size()==0){
res=query(1,m);
}else{
sort(g[i].begin(),g[i].end());
int len=g[i].size();
res=max(res,query(1,g[i][0]-1));
for(int j=0;j<len-1;j++){
res=max(res,query(g[i][j]+1,g[i][j+1]-1));
}
res=max(res,query(g[i][len-1]+1,m));
}
ans=max(ans,res+a[i]);
}
printf("%lld\n",ans);
return 0;
}

浙公网安备 33010602011771号