HDU - 6709 Fishing Master(贪心)

传送门


题目大意

有一个池塘里面有 n n n条鱼,每条鱼煮熟的时间最少为 t i t_i ti(可以多煮一会但不能少),现在钓每条鱼的时间均为 k k k。只有一口锅,也就是说鱼只能一条一条的煮,且只能一条一条的钓,在煮鱼的同时可以钓鱼,问煮完所有鱼最少花费的时间是多少?

解题思路

首先因为每条鱼都必须钓出来,因此总的钓鱼的时间是固定的 k ∗ n k * n kn。能节约的时间其实也就是在钓鱼的时候顺带煮鱼,又因为第一条鱼必须先钓出来才能煮,因此必须在 k ∗ ( n − 1 ) k*(n - 1) k(n1)的时间内充分利用时间去煮鱼。

考虑最好的情况,也就是所有煮鱼的时间刚好抵消了钓鱼的时间,那么就是 ∑ t i + k \sum{t_i} + k ti+k。实际上需要讨论清楚的就是对于 t i % k t_i \% k ti%k 这段时间内,是等待还是继续钓鱼?若手上有鱼的话,显然等待是最优的,因为这样可以尽可能完整地利用下次钓鱼的时间,只需等当前的鱼煮完然后再放上已经钓好的一条鱼然后继续钓鱼;否则只能继续钓鱼,因为即使等待的话下次钓鱼的时间只做一件事,这样相当于浪费了一次钓鱼时可以煮鱼的机会,那么就需要在 t i % k t_i \%k ti%k 的时间内钓一条鱼,这样一定要浪费了 k − t i % k k - t_i \%k kti%k 的时间,为了保证浪费的时间最少,那么只需要尽可能保证先钓模 k k k 余数大的鱼。

对于上述过程,如果模拟的话,比钓余数更大的鱼更优先的是先钓除以 k k k 的商更大的鱼,这样能保证接下来的很多个回合都可以边煮边钓,能保证手上有鱼的话最终的答案就会更接近最优情况。

但是我们并不需要模拟上述过程,因为上述第二个过程可以看做可钓的鱼中没有除以 k k k 商大于 0 0 0 的了(否则就可以维持一个均衡),因此只需要考虑在 n − 1 n - 1 n1 k k k 中,所有的鱼能充分利用多少,实际上就是累加 s u m = ∑ ⌊ t i k ⌋ sum = \sum{\lfloor \frac{t_i}{k} \rfloor} sum=kti n − 1 n - 1 n1比较大小:

  • s u m ≥ n − 1 sum \geq n - 1 sumn1,显然可以达到最优情况,这时答案就是 k ∗ n + ∑ t i % k k * n + \sum{t_i \%k} kn+ti%k
  • s u m < n − 1 sum < n - 1 sum<n1, 需要在小于 k k k 的时间内去钓鱼,有 n − 1 − s u m n - 1 -sum n1sum条鱼需要执行第二个操作,因此所有的鱼安装余数降序,取前缀的鱼执行第二个操作,那么只需要累加除去这段前缀的后缀的余数和即 k ∗ n + ∑ i = 1 n t i % k − ∑ i = 1 n − 1 − s u m t i % k k *n + \sum_{i = 1}^nt_i \%k - \sum_{i = 1}^{n - 1 - sum}t_i \%k kn+i=1nti%ki=1n1sumti%k
#include <bits/stdc++.h>

#include <unordered_map>
using namespace std;
#define ENDL "\n"
typedef long long ll;
typedef pair<int, int> pii;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6;
const int Mod = 1e9 + 7;
const int maxn = 1e5 + 10;

struct node {
    
    
    int x;
    int y;
    int res;

    bool operator<(const node &p) const {
    
     return res > p.res; }
} a[maxn];

ll sum[maxn];

int main() {
    
    
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T, n, k;
    cin >> T;
    while (T--) {
    
    
        cin >> n >> k;
        ll num = 0;
        for (int i = 1; i <= n; i++) {
    
    
            cin >> a[i].x;
            a[i].y = a[i].x / k;
            num += a[i].y;
            a[i].res = a[i].x % k;
        }
        sort(a + 1, a + 1 + n);
        for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i].res;
        ll ans = 1LL * k * n;
        if (num >= n - 1)
            ans += 1LL * (num - n + 1) * k + sum[n];
        else {
    
    
            ans += sum[n];
            ans -= sum[n - 1 - num];
        }
        cout << ans << ENDL;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44691917/article/details/117171065
今日推荐