USACO 2024 December Contest, Gold

Problem 3. Job Completion

Bessie the cow has NN (1≤N≤2⋅1051≤N≤2⋅105) jobs for you to potentially complete. The ii-th one, if you choose to complete it, must be started at or before time sisi and takes titi time to complete (0≤si≤1018,1≤ti≤10180≤si≤1018,1≤ti≤1018).

What is the maximum number of jobs you can complete? Time starts at 00, and once you start a job you must work on it until it is complete, without starting any other jobs in the meantime.

INPUT FORMAT (input arrives from the terminal / stdin):

The first line contains TT, the number of independent test cases (1≤T≤101≤T≤10). Each test case is formatted as follows.

The first line contains NN.

Each of the next NN lines contains two integers sisi and titi. Row i+1i+1 has the details for the iith job.

It is guaranteed that the sum of NN over all test cases does not exceed 3⋅1053⋅105.

OUTPUT FORMAT (print output to the terminal / stdout):

For each test case, the maximum number of jobs you can complete, on a new line.

SAMPLE INPUT:
3
2
1 4
1 2
2
2 3
1 2
3
1 4
2 3
1 2
SAMPLE OUTPUT:
1
2
2

For the first test case, you can only complete one of the jobs. After completing one job, it will then be time 22 or later, so it is too late to start the other job, which must be started at time 11 or earlier.

For the second test case, you can start the second job at time 00 and finish at time 22, then start the first job at time 22 and finish at time 55.

SCORING:

  • Inputs 2: Within the same test case, all titi are equal.
  • Inputs 3-4: N≤2000N≤2000, si,ti≤2000si,ti≤2000
  • Inputs 5-8: N≤2000N≤2000
  • Inputs 9-16: No additional constraints.

从第三题开始,tldr每个工作有一个截止时间但是必须从si开始,已知时长ti,不能同时做很多工作,接着就是解题目标,求出最多能完成多少工作。所以是很明显的贪心问题。首先选择为每个工作的开始和时长做排序,(si+ti)再检查每个工作是否可以跟前者确定的基础上完成。

错误答案是土使用dp方法但是会超时:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct Job {
    long long start, time;
};

int solve() {
    int n;
    cin >> n;
    
    vector<Job> jobs(n);
    for(int i = 0; i < n; i++) {
        cin >> jobs[i].start >> jobs[i].time;
    }
     
    vector<int> dp(n + 1, 0);
     
    for(int i = 0; i < n; i++) { 
        for(long long start = 0; start <= jobs[i].start; start++) {
            long long finish = start + jobs[i].time;
            int count = 1;
             
            for(int j = 0; j < n; j++) {
                if(j != i && finish <= jobs[j].start) {
                    long long next_finish = jobs[j].start + jobs[j].time;
                    count++;
                    finish = next_finish;
                }
            }
            dp[i] = max(dp[i], count);
        }
    }
    
    int result = 0;
    for(int i = 0; i < n; i++) {
        result = max(result, dp[i]);
    }
    return result;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    
    int t;
    cin >> t;
    
    while(t--) {
        cout << solve() << "\n";
    }
    
    return 0;
}

优化v1:

第一步,最重要的是知道sort的过程,这个版本只采用了start time si排序,接下来要确保完成工作的顺序是si+ti

#include <bits/stdc++.h>
#include <climits>
using namespace std;

using ll = long long;

int main() {
	cin.tie(0)->sync_with_stdio(0);
	int T;
	cin >> T;
	for (int t = 0; t < T; ++t) {
		int N;
		cin >> N;
		vector<pair<ll, ll>> tasks;
		for (int n = 0; n < N; ++n) {
			ll s, t;
			cin >> s >> t;
			tasks.push_back({s, t});
		}
		sort(begin(tasks), end(tasks));
		ll time_so_far = 0;
		int ans = 0;
		for (auto [s, t] : tasks) {
			if (time_so_far <= s) {
				++ans;
				time_so_far += t;
			}
		}
		cout << ans << "\n";
	}
}
#include <bits/stdc++.h>
#include <climits>
using namespace std;

using ll = long long;

int main() {
	cin.tie(0)->sync_with_stdio(0);
	int T;
	cin >> T;
	for (int t = 0; t < T; ++t) {
		int N;
		cin >> N;
		vector<pair<ll, ll>> tasks;
		for (int n = 0; n < N; ++n) {
			ll s, t;
			cin >> s >> t;
			ll d = s + t;
			tasks.push_back({d, t});
		}
		sort(begin(tasks), end(tasks));
		vector<ll> dp{0};
		for (auto [d, t] : tasks) {
			dp.push_back(LLONG_MAX);
			for (int i = size(dp) - 2; i >= 0; --i)
				dp.at(i + 1) = min(dp.at(i + 1), dp.at(i) + t);
			while (dp.back() > d) dp.pop_back();
		}
		cout << size(dp) - 1 << "\n";
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值