Problem - F - Codeforces
有n个任务。如果你完成第i个任务,你将获得ai币。你每天最多只能完成一个任务。然而,一旦你完成了一个任务,在K天内你不能再做同样的任务。(例如,如果k=2,你在第1天做了任务1,那么你在第2天或第3天不能做,但你可以在第4天再做)。
给你两个整数c和d。找出k的最大值,使你在d天内至少能获得c个硬币。如果不存在这样的k,则输出Impossible。如果k可以是任意大的,则输出Infinity。
输入
输入由多个测试案例组成。第一行包含一个整数t(1≤t≤104)--测试案例的数量。测试用例的描述如下。
每个测试用例的第一行包含三个整数n,c,d(2≤n≤2⋅105;1≤c≤1016;1≤d≤2⋅105)--任务的数量,你需要的硬币数量,以及天数。
每个测试案例的第二行包含n个整数a1,a2,...,an(1≤ai≤109)--任务的奖励。
所有测试案例的n之和不超过2⋅105,所有测试案例的d之和不超过2⋅105。
输出
对于每个测试用例,输出以下结果之一。
如果不存在这样的k,输出Impossible。
如果k可以是任意大的,则输出Infinity。
否则,输出一个整数--k的最大值,使你在d天内至少能获得c个硬币。
请注意,检查器是区分大小写的,你应该完全按照给出的字符串来输出。
例子
inputCopy
6
2 5 4
1 2
2 20 10
100 10
3 100 3
7 2 6
4 20 3
4 5 6 7
4 100000000000 2022
8217734 927368 26389746 627896974
2 20 4
5 1
输出拷贝
2
杅眕
不可能的
1
12
0
备注
在第一个测试案例中,在k=2的情况下,在4天内赚取5个金币的方法如下。
第1天:做任务2,赚取2个金币。
第二天:做任务1,赚取1个金币。
第三天:什么都不做。
第四天:做任务2,赚取2个硬币。
总的来说,我们赚了2+1+2=5个硬币。
在第二个测试案例中,我们可以通过做第一个任务赚取100个硬币,在第一天本身就可以赚取超过20个硬币,所以k的值可以任意大,因为我们从来不需要做另一个任务。
在第三个测试案例中,无论我们怎么做,我们都无法在3天内赚到100个硬币。
题解:
首先我们把无限,与不可能的情况去除,
什么时候无限,就是,min(d,n)个前最大的相加>=c,不需要重复加最大的都可完成,
不可能则是每天都是最大的*d都无法达到c,就是不可能
然后就是二分k的最大值,因为根据k的大小,钱数的大小肯定也是单调的
关键是check函数怎么写,
这里看了一下大佬的,觉得写的很简洁,很不错
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define int long long
int a[200050];
void solve()
{
long long n,c,d;
cin >> n >> c>>d;
for(int i = 1;i <= n;i++)
{
cin >> a[i];
}
sort(a+1,a+1+n,greater<int>());
long long s = 0;
for(int i = 1;i <= min(n,d);i++)
s+= a[i];
if(s >= c)
{
cout<<"Infinity\n";
return ;
}
if(a[1]*d < c)
{
cout<<"Impossible\n";
return ;
}
int l = 0,r = 2e5;
while(l < r)
{
int mid = (l + r+1)/2;
s = 0;
for(int i = 1;i <= d;i++)
{
int id = ((i-1) % (mid+1)+1);
if(id <= n)
{
s += a[id];
}
}
if(s >= c)
{
l = mid;
}
else
{
r = mid-1;
}
}
cout<<l<<"\n";
}
signed main()
{
int t = 1;
cin >> t;
while(t--)
{
solve();
}
}