Title

CF1379C Choosing flowers 题解

解题思路

不是那么显然的,当只选一种 bi 或全选 ai 时最优。那么我们可以先对 ai 从大到小排序,枚举每一个 bi,然后二分找到第一个大于等于 biaj,判断 a1aj 中是否包含 ai,如果包含,当前的答案为 (k=1jak)+bi×(nj),否则当前答案为 (k=1jak)+ai+bi×(nj1),最后对于所有答案取最大值即可。

对于只选一种 bi 最优证明如下:

  • 若当前 bi 最大,若 aj>bi,那么 aj 一定位于前缀和中,此时若选择 bi 且选择 bj,那么可以看作用 bj 替换了一个 bi,又有 bi>bj,那么答案一定小于只选一种的答案;若 aj<bi,那么一定不会选择用更小的 aj 替换更大的 bi
  • 若当前 bi 不为最大,若 aj>bi,在 bj 大于 bi 时,全选 bi 更优,在 bj<bi 时,同上;若 aj<bi,那么若 bj>bi,则答案一定会在全选 bj 或全选 bi 中取,证明如上,若 bj<bi,则一定不优;
  • aj=bibj=bi 情况均同上。

综上,只选一种 bi 或全选 ai 为最优决策,因此可以枚举找到答案。

AC 代码

#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#define N 100005
#define ll long long
int n,m;
struct Flower{
    int a,b;
}a[N];ll sum[N];
inline bool cmp(Flower x,Flower y){
    if(x.a!=y.a)
        return x.a>y.a;
    return x.b>y.b;
}
inline int Upper(int x){
    int l=1,r=m,res=0,mid;
    while(l<=r){
        mid=(l+r+1)>>1;
        if(a[mid].a>=x){
            res=mid;
            l=mid+1;
        }else r=mid-1;
    }return res;
}
inline void work(){
    scanf("%d%d",&n,&m);int k=m;
    int maxt=-1, maxi=0;ll ans=0;
    for(register int i=1;i<=m;++i){
        scanf("%d",&a[i].a);
        scanf("%d",&a[i].b);
        if(a[i].b>maxt) maxt=a[i].b;
    }std::sort(a+1,a+m+1,cmp);
    for(register int i=1;i<=m;++i)
        sum[i]=sum[i-1]+a[i].a;
    if(n<=m) ans=sum[n];
    else ans=sum[m]+1ll*(n-m)*maxt;
    for(register int i=1;i<=m;++i){
        int x=Upper(a[i].b);
        if(x>n) continue;
        ll now=sum[x],res;
        if(x>=i) res=1ll*a[i].b*(n-x);
        else res=a[i].a+1ll*(n-1-x)*a[i].b;
        if(now+res>ans) ans=now+res;
    }printf("%lld\n",ans);
}
signed main(){
    int T;scanf("%d",&T);
    while(T--) work();
}
posted @   UncleSam_Died  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示