跳转至

CF1650F Vitaly and Advanced Useless Algorithms

T16:53:00+08:00 CodeForces:Problem - F - Codeforces

洛谷:CF1650F Vitaly and Advanced Useless Algorithms - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

「题意」

\(n\) 个任务,每个任务要在 \(a_i\) 时刻前做完。(\(a\) 升序)

\(m\) 个计划,每个计划最多只能执行一次,每个计划由 \(e_i\), \(t_i\), \(p_i\) 描述:如果执行了第 \(i\) 个计划,那么 \(t_i\) 时间后,任务 \(e_i\) 会被完成 \(p_i\) 的百分比。

输入 \(T\) 组数据。

输出每组执行的计划个数 \(k\),并按顺序输出执行的计划(若不行则输出 -1,若有多种方案输出其中一种即可)。

「思路」

首先显然有一个贪心的结论:在当前任务未完成时,优先选择能对当前任务有进展的计划(优先完成离ddl近的任务)。

那么对于每一个任务的目标就是 能使进度达到100%的最少时间

很容易借助 差分 得到 每一个任务的限制时间

对于每一个任务,就是个 01背包,对于每一个计划选择 执行不执行

在当前任务省下来的时间,就可以添加到下一个任务的时间中去。

「码」

C++
#include <iostream>
#include <cstring>
#include <tuple> // 元组 c++11
#include <vector>

#define INF 0x7f
#define ll long long

using namespace std;

const int MAXN = 1E5 + 7;

int a[MAXN];
ll dp[200 + 7]; // 最少时间
bool f[MAXN][200 + 7];

int solveTask(int a, vector<tuple<int, int, int>> &plans, vector<int> &ans) {
    // memset(f, 0, sizeof(f));
    memset(dp, INF, sizeof(dp));
    dp[0] = 0;

    int n = plans.size();
    int endk = 0;
    for (int j = 0; j < n; j++) {
        auto [e, t, p] = plans[j]; // 结构化绑定 c++17, auto 自动类型推断 c++11
        for (int k = 200; k >= 0; k--) {
            if (k >= p && dp[k - p] + t < dp[k]) {
                dp[k] = dp[k - p] + t;
                f[j][k] = 1;
                if (k >= 100 && dp[k] <= a && (dp[k] < dp[endk] || endk == 0)) {
                    endk = k;
                }
            } else {
                f[j][k] = 0;
            }
        }
    }

    if (endk == 0) return -1;
    int k = endk, j = n-1;
    for (int j = n-1; j >= 0 && k; j--) {
        if (f[j][k]) {
            auto [e, _, p] = plans[j]; // 结构化绑定 c++17, auto 自动类型推断 c++11
            ans.emplace_back(e); // 在vector末尾原位构造 c++11
            k -= p;
        }
    }
    return dp[endk];
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int T; cin >> T;

    int n, m;
    while (T--) {
        cin >> n >> m;

        a[0] = 0;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            a[i-1] = a[i] - a[i-1];
        }

        vector<vector<tuple<int, int, int>>> plans(n); // 元组 c++11
        for (int i = 1, _e, _t, _p; i <= m; i++) {
            cin >> _e >> _t >> _p;
            plans[_e - 1].emplace_back(i, _t, _p); // 在vector末尾原位构造 c++11
        }

        bool f = 0;
        vector<int> ans;
        int saved_time = 0;
        for (int i = 0; i < n; i++) {
            a[i] += saved_time;
            int mint = solveTask(a[i], plans[i], ans);
            if (mint < 0) {
                f = 1;
                break;
            }
            saved_time = a[i] - mint;
        }

        if (f) {
            cout << -1 << endl;
        } else {
            cout << ans.size() << endl;
            // auto 自动类型推断 c++11
            for (auto iter = ans.begin(); iter != ans.end(); iter++) {
                cout << *iter << ' ';
            }
            cout << endl;
        }
    }

    return 0;
}

「几个坑点」

看到那个注释掉的 memset() 没!

大坏蛋!

调了一个小时,问了别人才知道这个 memset() 可能会导致超时!

原因是 f 数组太大了,且这个 memset 在每个 case 中都被调用了 n 次!

这回我可记住了!

评论