题解 CF1760F Quests
大家好,我是 CQ-C2024 蒟蒻 CJH。
(最近一次更新:2022/12/20 21:16,发现 $k$ 无解的情况笔误,已修改,感谢 @budaiyanjing 的提醒)
题意
有 $n$ 个任务,完成第 $i$ 个任务可以获得 $a_i$ 个金币,完成一个任务在未来 $k$ 天内不能再次完成。你要在 $d$ 天内获得 $c$ 个金币,求最大的 $k$。
分析思路
貌似看各位大佬都是用的二分,我这里补一篇贪心排序的题解。
首先将 $a$ 数组从大到小排序,$k$ 此时有三种情况:
一、$k$ 无解
考虑最坏的情况,如果 $k=0$ 时,在 $d$ 天都做利润最高的那个任务,如果仍不能达到 $c$ 个,即 $d \times a_1 < c$,则判定为无解。
二、$k$ 为无穷大
在这 $d$ 天内,将所有的任务只做一遍即可达到 $c$ 个,即 $\sum\limits_{i=1}^{\min\{d,n\}}a_i \ge c$,则 $k$ 为无穷大。
三、$k$ 有解
这里在 $d-1 \sim 0$ 中枚举 $k$,我们将每 $k+1$ 视为一个循环,且每个循环中做最大利润的任务,余下的天数就做利润从大到小的任务。
注意事项
$c\le 10^{16}$,需要用 long long 存储,不开 。long long 见祖宗
代码
//the code is from chenjh
#include<bits/stdc++.h>
#define MAXN 200002
using namespace std;
typedef long long LL;
int a[MAXN];
LL b[MAXN];
void solve(){
int n,d;LL c;
scanf("%d%lld%d",&n,&c,&d);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+n+1,greater<int>());//从大到小排序。
if((LL)a[1]*d<c){puts("Impossible");return;}//判断无解。
for(int i=1;i<=n;i++) b[i]=b[i-1]+a[i];//前缀和数组,表示前 i 个任务的利润。
if(b[min(n,d)]>=c){puts("Infinity");return;}//判断是否无穷大。
int k;
for(k=d-1;k>=0;k--){//枚举 k。
int x=d%(k+1);//判断余下的天数。
if(b[min(n,x)]+d/(k+1)*b[min(n,k+1)]>=c){//一定要取最小值,要不然就会访问到 n 个任务以外!
printf("%d\n",k);
return;
}
}
puts("Impossible");
}
int main(){
int t;scanf("%d",&t);
while(t--) solve();
return 0;
}

浙公网安备 33010602011771号