Codeforces1379 C. Choosing flowers(贪心+二分)

题意:

有m种花,每种的数量无限,每朵花有a(i)和b(i)。
现在你需要挑出n朵花,第一次挑选某种花的时候,权值增加a(i),之后每次都只增加b(i)
问挑选n朵花能得到的最大权值是多少。

数据范围:m<=1e5,n<=1e9

解法:

如果某种花要购买多次,那么之后每次增加的权值是b(i),
一种想法是选出b(i)最大的,如果买超过一朵就都买这种花,
贪心一下,买这个b(i)之前,把所有大于这个b(i)的其他a(i)都买下来。

但是这种做法有一个问题,就是最大的b(i)本身对应的a(i)可能很小,
例如:
2 2
11 9
1 10
这组数据第二种花的b(i)很大,但是a(i)很小,就不成立了。

但是从上面的想法可以推测出,最多只有一种花买超过一朵,
那么枚举这个超过一朵的花,优先买大于b(i)的其他a(i)花,然后剩下的全买这种就行了,对答案取max
找大于b(i)的花可以用排序+二分做

需要注意的点:
如果a(i)>b(i),那么买大于b(i)的花的时候已经买了当前a(i)
如果a(i)<=b(i),那么还需要多花费一次机会买当前a(i)

code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=1e5+5;
struct Node{
    int a,b;
}a[maxm];
int sum[maxm];
int c[maxm];
int n,m;
bool cmp(int a,int b){
    return a>b;
}
signed main(){
    int T;cin>>T;
    while(T--){
        cin>>n>>m;
        for(int i=1;i<=m;i++){
            cin>>a[i].a>>a[i].b;
            c[i]=a[i].a;
        }
        sort(c+1,c+1+m,cmp);//从大到小排序
        for(int i=1;i<=m;i++){
            sum[i]=sum[i-1]+c[i];
        }
        int ans=0;
        for(int i=1;i<=m;i++){//枚举最后b[i]买的是哪种
            int temp=0;
            int remain=n;
            //二分找>b[i]的
            int l=1,r=m;
            int p=-1;
            while(l<=r){
                int mid=(l+r)/2;
                if(c[mid]>a[i].b){
                    p=mid,l=mid+1;
                }else{
                    r=mid-1;
                }
            }
            if(p==-1){//没有>b[i]的,那么全买这一种
                ans=max(ans,a[i].a+(n-1)*a[i].b);
                continue;
            }
            //
            if(p>n)p=n;
            temp+=sum[p];
            remain-=p;
            if(a[i].a>=c[p]){
                temp+=a[i].b*remain;
            }else{
                if(remain){
                    temp+=a[i].a;
                    remain--;
                    temp+=a[i].b*remain;
                }
            }
            //
            ans=max(ans,temp);
        }
        cout<<ans<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/107478619