比赛链接:

https://codeforces.com/contest/1650

E. Rescheduling the Exam

题目大意:

要通过 \(n\) 场考试,考试时间在 1 到 \(d\) 之间,第 i 场考试在第 \(a_i\) 天,每场考试之间的时间间隔就是休息时间,现在可以改变某一场考试的时间,让它任意换一个时间考试,要求最大化所有考试之间的休息时间的最小值,并输出答案。

思路:

首先找到哪两场之间休息时间最短,我们尝试移动其中一场考试的考试时间,让结果最大化。
根据贪心的策略,我们容易想到,这一场考试只可能移动到休息时间最大的两场考试之间,或者把它放在最后一天考。考虑一个特殊情况,即我们找到的最小休息时间是 0 到第一场考试的时候,前面那个就没法移动了。
那么这样子我们的答案就是在这两者中取一个大,然后再与所有休息时间中最小的那个取一个最小值。

代码:

#include <bits/stdc++.h>
using namespace std;
#define IOS() ios::sync_with_stdio(false);cin.tie(nullptr);
#define LL long long
#define pb push_back
const int N = 2e5 + 10, INF = 1e9 + 10;
LL T, n, d;
LL cal(vector <LL> &t){
	LL mx = 0, mn = INF;
	for (int i = 1; i < n; ++ i){
		mx = max(mx, t[i] - t[i - 1] - 1);
		mn = min(mn, t[i] - t[i - 1] - 1);
	}
	return min( mn, max(d - t[n - 1] - 1, (mx - 1) / 2) );
}
void solve(){
	cin >> n >> d;
	vector <LL> a(n + 1);
	for (int i = 1; i <= n; ++ i)
		cin >> a[i];
	LL mn = INF, p;
	for (int i = 1; i <= n; ++ i)
		if (mn > a[i] - a[i - 1] - 1){
			mn = a[i] - a[i - 1] - 1;
			p = i;
		}
	vector <LL> t;
	for (int i = 0; i <= n; ++ i)
		if (i != p)
			t.pb(a[i]);
	LL ans = cal(t);
	if (p > 1)
		t[p - 1] = a[p];
	ans = max(ans, cal(t));
	cout << ans << "\n";
}
int main(){
	IOS();
	cin >> T;
	while (T--)
		solve();
	return 0;
}

F. Vitaly and Advanced Useless Algorithms

题目大意:

\(n\) 个任务要完成,每个任务都有一个 \(deadline a_i\),即在第 \(a_i\) 小时及之前要完成该任务,刚开始每个任务的完成度都是 0%,当完成度达到 100% 或以上的时候该任务完成。
现在有 \(m\) 个计划,第 \(i\) 个计划有三个数 \(e_i\)\(t_i\)\(p_i\),表示如果选了这个计划就会在当前时间开始的 \(t_i\) 小时后完成 \(p_i\)% 的任务 \(e_i\),这段时间不能做其它任务,且每一个任务只能进行一次。
时间从 0 开始,先要求找到一个执行计划的顺序来完成所有任务,若找不到输出 -1。

思路:

我们可以先按照每个计划完成的任务进行分类,这样子就得到了能完成每个任务的所有计划。
接下来就是找到一个执行计划的方案,用最短的时间,让这个计划的完成度达到 100% 或以上,因为每个计划只能执行一次,可以看出是一个 01背包问题
背包容量为 100,即完成度,每个计划看成一个物品,物品的价值是时间,重量是完成度,求最小的时间,做 01背包,并求出具体方案。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define IOS() ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define pb push_back
const int INF = 1e9 + 10;
struct node{
	LL t, p, id;
};
void solve(){
	LL n, m;
	cin >> n >> m;
	vector <LL> a(n);
	vector <node> v[n + 1];
	for (int i = 0; i < n; ++ i)
		cin >> a[i];
	for (int i = 0; i < m; ++ i){
		LL e, t, p;
		cin >> e >> t >> p;
		v[e].pb({t, p, i + 1});
	}
	LL s = 0;
	vector <LL> ans;
	for (int i = 1; i <= n; ++ i){
		vector <LL> dp(101, INF), pre[101];
		dp[0] = 0;
		for (auto x : v[i]){
			for (int j = 100; j >= 0; -- j){
				if (dp[j] > dp[max(0LL, j - x.p)] + x.t){
					dp[j] = dp[max(0LL, j - x.p)] + x.t;
					pre[j] = pre[max(0LL, j - x.p)];
					pre[j].pb(x.id);
				}
			}
		}
		s += dp[100];
		if (s > a[i - 1]){
			cout << "-1\n";
			return;
		}
		for (auto x : pre[100])
			ans.pb(x);
	}
	cout << ans.size() << "\n";
	for (int i = 0; i < ans.size(); ++ i)
		cout << ans[i] << " \n"[i == ans.size() - 1];
}
int main(){
	IOS();
	LL T;
	cin >> T;
	while (T--)
		solve();
	return 0;
}

G. Counting Shortcuts

题目大意:

\(n\) 个点,\(m\) 条边的无向图,图中没有自循环和重边,每条边长度为 1。找到点 \(s\) 到点 \(t\) 的所有长度与它们两点间最短路径长度差值不超过 1 的路径数量。

思路:

首先考虑长度等于最短路径长度的路径,一遍 \(bfs\) 就可以求出来。
然后找差值为 1 的路径,显然,不可能有比最短距离小 1 的路径(有的话,那最短路径还是最短路径嘛),所以只有比最短距离大 1 的路径。
记一条最短路的起点为 \(s\),终点为 \(t\),该路径上一个点为 \(u\),路径外的一个点为 \(v\)。若 \(u\)\(v\) 的最短路径为 1,那么 \(s -> u -> v -> t\) 这条路径就是一条差值为 1 的路径。
\(d(a, b)\)\(a\)\(b\) 的最短距离,\(k\)\(s\)\(t\) 的最短路径。
只要满足了 \(d(s, u) + 1 + d(v, t) = k + 1\)\(d(s, u) + d(u, t) = k\) 这两个条件,那么这就是一条比最短距离大 1 的路径,要计算进最后的答案。

代码:

#include <bits/stdc++.h>
using namespace std;
#define IOS() ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define LL long long
#define pb push_back
const int mod = 1e9 + 7, N = 2e5 + 10;
LL T = 1, n, m, s, t;
void solve(){
	cin >> n >> m >> s >> t;
	vector < vector <LL> > e(n + 1);
	for (int i = 1; i <= m; ++ i){
		LL u, v;
		cin >> u >> v;
		e[u].pb(v);
		e[v].pb(u);
	}
	auto bfs = [&] (LL x){
		vector <LL> d(n + 1, - 1), f(n + 1);
		d[x] = 0;
		f[x] = 1;
		queue <LL> q;
		q.push(x);
		while (q.size()){
			LL u = q.front();
			q.pop();
			for (auto v : e[u]){
				if (d[v] == -1){
					d[v] = d[u] + 1;
					q.push(v);
				}
				if (d[v] == d[u] + 1)
					f[v] = ( f[u] + f[v] ) % mod;
			}
		}
		return pair(d, f);
	};
	auto [ds, fs] = bfs(s);
	auto [dt, ft] = bfs(t);
	LL ans = fs[t];
	for (LL u = 1; u <= n; ++ u)
		for (auto v : e[u])
			if (ds[u] + dt[v] == ds[t] && ds[u] + dt[u] == ds[t])
				ans = ( (fs[u] * ft[v]) % mod + ans) % mod;
	cout << ans << "\n";
}
int main(){
	IOS();
	cin >> T;
	while(T--)
		solve();
	return 0;
}

posted on 2022-03-10 18:54  Hamine  阅读(139)  评论(0编辑  收藏  举报