AT_abc331_e [ABC331E] Set Meal 题解

题意

给定L个二元组(ci,di),再从n个数字aim个数字bi各选取一个数组成一个二元组(ai,bj),使得二数之和最大并且满足(i,j)不是L个元组的子集。

数据范围

  • 1  N, M  105
  • 0  L  min(105, N M  1)

思路

先考虑没有L个二元组限制时我们是如何处理的,显然,先把求出b数组中的最大值再在a数组枚举答案。时间复杂度为O(n)

现在考虑有条件限制的情况,很容易发现对于一个i,把它不能与它配对的j排序后的数组为g,那么对于所有x都可以在g[k]+1 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;
}
posted @   CQWYB  阅读(8)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示