Codeforces #657 Div2C choosing flowers

看错时间导致错过一场比赛......

题意,有m种无限多的物品,有两个价值(a[i],b[i]),若选x[i](x[i] >= 1)个,则能获得(a[i] + (x[i] - 1) * b[i])的价值(若不选则价值为0)

求选出n个,使得价值最大.m<=1e5,n,a[i],b[i]<=1e9;

分析:这个数据范围大概就是要贪心了,然后考虑怎么贪.我们发现,若只选一个,实质上只有a[i]在起作用,只有选两个以上,b[i]才有影响.可以猜测出要么所有的都只选一个,要么只有一种物品选超过一个.

证明如下:

设第i个物品选的个数为cnt[i],对于任意的i,j,若cnt[i],cnt[j]>=1,设b[i] >= b[j],则显然如果接下来还有若干个选择机会,选第i个物品一定比选j个物品优,因为既然都选了一次后,价值就与a[i]无关了,所以选择的贡献b[i] >= b[j].

所以我们可以枚举哪种物品要选超过一次.显然我们如果枚举到第i个物品,可以先钦定x[i]  = n,即n个物品全选x[i],然后对于(j != i && a[j] > b[i]),再反悔一次,选择a[j],这个过程可以先排序,然后二分大于b[i]的a[j],前缀和加一下即可

记得特判所有物品都只选一种的情况

时间复杂度(nlogn)

(挺简单一道题,不知道为什么只有1000来个人过)

/*C. Choosing flowers*/ 
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 1e6 + 10;
#define ll long long
struct Num{
    int fir,sec,id;
    bool operator < (Num A){
        return fir < A.fir; 
    }
}a[maxn];
ll sum[maxn];
int n,m;
int read(){
    char ch = getchar();
    int x = 0;
    while(ch < '0' || ch > '9')        ch = getchar();
    while(ch >= '0' && ch <= '9')    x = x * 10 + ch - 48,ch = getchar();
    return x;
}
int get(int x){
    int l = 1,r = m;
    int ans = 0;
    while(l <= r){
        int mid = (l + r) >> 1;
        if(a[mid].fir <= x){
            l = mid + 1;
            ans = mid;
        }
        else{
            r = mid - 1;
        }
    } 
    return m - ans;
}
int main()
{
    int t = read();
    while(t--){
        n = read(),m = read();
        for(int i = 1; i <= m; ++i){
            a[i].fir = read();
            a[i].sec = read();
            a[i].id = i;
        }
        sort(a+1,a+m+1);
        for(int i = 1; i <= m; ++i)
            sum[i] = sum[i-1] + a[i].fir;
        ll ans = 0;
        if(n <= m){
            ans = sum[m] - sum[m - n];
        }
        for(int i = 1; i <= m; ++i){
            int k = get(a[i].sec);
            ll res = sum[m] - sum[m - k];
            if(a[i].fir <= a[i].sec){
                k++;
                res += a[i].fir;
            }
            if(k >= n)    continue;
            else{
                res += 1ll * (n - k) * a[i].sec;
                ans = max(ans,res);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted @ 2020-07-19 20:10  y_dove  阅读(180)  评论(0编辑  收藏  举报