比赛链接:
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;
}