SCUT校赛131:小P玩游戏II(贪心 & 思维)

题目描述

PP最近迷上了一个游戏,但他在玩游戏的时候遇到了一个问题。

PP控制nn 个角色,标号为11nn,小PPKK个怪物可以分配给这nn个角色击杀,一个怪物只能分配给一个角色,并且必须要分配给一个角色。

对于第 i\,(1 \leq i \leq n)i(1in)个角色,如果没有分配到一个怪物,那么它就会获得经验c_ici,如果分配到了t\,(t \geq 1)t(t1)个怪物,那么它会获得经验a_i + t b_iai+tbi

PP要把KK个怪物分配给这nn个角色,问所有角色获得的经验总和最多是多少。


输入格式

输入第一行一个整数TT,表示有TT组数据。

对于每组数据,第一行两个正整数nnKK

接下来nn行,每行三个整数a_i,b_i,c_iai,bi,ci

1 \leq T \leq 501T50

1 \leq n, K \leq 1000001n,K100000

1 \leq a_i, b_i, c_i \leq 1000001ai,bi,ci100000


输出格式

对于每组数据,输出一个整数表示答案。


样例数据

输入

2
2 2
4 1 1
1 3 3
2 2
4 1 1
1 3 4

输出

9
10

备注


思路:(参考题解和师兄的代码)最佳分配的情况是这样的,分配到>1只怪的人一定<=1个,而这个人又是已分配到怪里面的人b值最大的,其余未分配到怪的人ai+bi-ci <= b,那么这个人是谁无法确定,所以枚举一下这个人就行。

# include <bits/stdc++.h>
# define ll long long
using namespace std;
const int maxn = 1e5;

struct node
{
    int a, b, c, d;
}m[maxn+3];

bool cmp(node x, node y)
{
    return x.d > y.d;
}

ll sum[maxn+3];
int main()
{
    int t, n, k;
    scanf("%d",&t);
    while(t--)
    {
        ll tot = 0;
        scanf("%d%d",&n,&k);
        for(int i=1; i<=n; ++i)
        {
            scanf("%d%d%d",&m[i].a, &m[i].b, &m[i].c);
            m[i].d = m[i].a + m[i].b - m[i].c;
        }
        sort(m+1, m+1+n, cmp);
        for(int i=1; i<=n; ++i)
            tot += m[i].c, sum[i] = sum[i-1] + m[i].d;
        ll ans = 0;
        for(int i=1; i<=n; ++i)
        {
            int l = 1, r = min(n,k-1);//k-1为上限是因为有一个怪已经分配给i了。
            while(l<=r)
            {
                int mid = l+r>>1;
                if(m[mid].d > m[i].b)
                    l = mid+1;
                else
                    r = mid-1;
            }
            if(r < i) ans = max(ans, (ll)tot + sum[r] + m[i].d + (ll)(k-r-1)*m[i].b);
            else ans = max(ans, (ll)tot + sum[r] + (ll)(k-r)*m[i].b);//这里比较巧妙,当r==k-1时这样处理貌似有bug,因为最佳可能是每个人分一个怪,但这里剩下的一个怪强制分给i了,然而枚举到最后一个人时又正确了。
        }
        printf("%lld\n",ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值