题意
有n条鱼,你钓一条鱼要k的时间,每条鱼有每条鱼的烹饪时间,问你最少的时间让所有的鱼都烹饪好。
注:钓鱼钓一半的时候不能去切换正在烹饪的鱼。
思路
首先讲两个东西
1、一条鱼(在烹饪的时候我跑去钓鱼)浪费的时间是 k - time%k
2、假设钓鱼没有浪费到我们的时间,我们至少要 a n s = ( k + 所 有 的 鱼 的 烹 饪 时 间 ) ans = (k + 所有的鱼的烹饪时间) ans=(k+所有的鱼的烹饪时间)
对所有的鱼从大到小排序,如果花费时间最大的那条鱼的时间<=k,那么答案肯定是
a
n
s
=
n
∗
k
+
a
[
n
]
ans = n*k + a[n]
ans=n∗k+a[n]
(a[n]是烹饪时间最短的那一条鱼)
对于那些烹饪时间%k==0和烹饪时间大于k的鱼,我们看在不浪费时间的情况下能攒多少条鱼。
1、如果攒下来的鱼大于等于我还没烹饪的鱼的条数,那么没有鱼浪费了我的时间,答案肯定是上面提到的 a n s ans ans
2、如果攒下来的鱼小于我还没烹饪的鱼的条数,我看还欠多少条鱼,然后取对应条数的尽可能少的浪费时间的鱼,就是答案了。
思路大体是这样,代码更容易看懂。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
ll t[maxn];
bool cmp(ll a, ll b)
{
return a > b;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int n;
ll k;
scanf("%d %lld", &n, &k);
ll sum = 0;
for(int i = 1; i <= n; i++)
{
scanf("%lld", &t[i]);
sum += t[i];
}
sort(t + 1, t + 1 + n, cmp);//从大到小排序
if(t[1] <= k)
{
printf("%lld\n", n * k + t[n]);
continue;
}
int fish = 1;//我现在手头有多少鱼
ll ans = k + sum;//花费的时间
int tem = n;//现在还剩下多少条鱼
for(int i = 1; i <= n; i++)
{
if(t[i] >= k)//如果这条鱼花费的时间大于等于k
{
fish += t[i] / k;
fish--;
tem--;
t[i] %= k;
}
}
if(fish >= tem)//如果不浪费情况下足够我们把鱼做完
{
printf("%lld\n", ans);
continue;
}
int need = tem - fish;//我还需要多少条鱼
sort(t + 1, t + 1 + n, cmp);
int new_n = n;
for(int i = 1; i <= n; i++)
{
if(t[i] == 0)
new_n--;
}
n = new_n;
for(int i = 1; i <= n; i++)
{
t[i] = k - t[i];//把它变成浪费的时间
}
sort(t + 1, t + 1 + n);
for(int i = 1; i <= need; i++)
{
ans += t[i];
}
printf("%lld\n", ans);
}
return 0;
}