Codeforces Round #787 (Div. 3)
阿新 • • 發佈:2022-05-08
比賽連結:
https://codeforces.com/contest/1675
F. Vlad and Unfinished Business
題目大意:
給定一棵 \(n\) 個節點的樹,邊權為 1,求出從點 \(x\) 出發,經過指定的 \(k\) 個點後,到達點 \(y\) 的最短路徑長度。
思路:
如果不去其它點,那最短路徑就是從 \(x\) 到 \(y\),通過一個數組記錄下來,從父節點到子節點的路徑為 1。
去往其它點的最短路徑的起點一定是 \(x\) 到 \(y\) 的最短路徑上的一個點,到了要去的點之後,回到起點,繼續向目的地進發,也通過一個數組記錄,從父節點到子節點的步數就為 2。
一遍 \(dfs\)
程式碼:
#include <bits/stdc++.h> using namespace std; const int N = 2e5 + 10; int T, k, n, x, y; bool work[N], to[N]; vector <int> g[N]; void init(){ for (int i = 1; i <= n; i ++ ){ work[i] = false; to[i] = false; g[i].clear(); } } void dfs(int u, int fa){ for (auto v : g[u]){ if (v != fa){ dfs(v, u); if (work[v]) work[u] = true; if (to[v]) to[u] = true; } } } void solve(){ cin >> n >> k >> x >> y; init(); for (int i = 1; i <= k; i ++ ){ int j; cin >> j; work[j] = true; } to[y] = true; for (int i = 1; i < n; i ++ ){ int u, v; cin >> u >> v; g[u].push_back(v); g[v].push_back(u); } dfs(x, 0); int ans = 0; for (int i = 1; i <= n; i ++ ){ if (i == x) continue; if (to[i]) ans ++ ; else if (work[i]) ans += 2; } cout << ans << "\n"; } int main(){ ios::sync_with_stdio(false);cin.tie(0); cin >> T; while (T -- ) solve(); return 0; }
G. Sorting Pancakes
題目大意:
\(m\) 個餅,分成 \(n\) 堆排成一排,每一步操作可以將第 \(i(i > 1)\)堆的餅取出一個放到第 \(i - 1\) 堆中,或將第 \(j(j < n)\)堆的餅取出放到第 \(j + 1\) 堆中。問最少多少步可以讓 \(n\) 堆餅的數量非遞增。
思路:
定義 \(dp[i][j][k]\) 為第 \(i\) 堆餅為 \(k\) 個,前 \(i\) 堆餅的數量總和為 \(j\) 個時讓前 \(i\) 堆餅的數量非遞增的最小移動次數。
第 \(i\) 堆餅的數量要小於第 \(i - 1\) 堆餅的數量,所以列舉第 \(i - 1\)
對於第 \(i\) 堆餅,因為前面 \(i - 1\) 堆已經排好了,那麼它要將多餘的餅移到後面去,或者將缺少的餅從後面移過來,所以先預處理一個字首和,第 \(i\) 位的移動步數就是字首和和 \(j\) 差值的絕對值。
可以得到轉移方程 \(dp[i][j][k] = min(dp[i][j][k], dp[i - 1][j - k][x] + \lvert s[i] - j \rvert)\)。
參考:https://zhuanlan.zhihu.com/p/510066695
程式碼:
#include <bits/stdc++.h>
using namespace std;
const int N = 255;
int n, m, a[N], dp[N][N][N], ans = 1e9;
int main(){
cin >> n >> m;
memset(dp, 0x3f, sizeof dp);
for (int i = 1; i <= n; i ++ ){
cin >> a[i];
a[i] += a[i - 1];
}
dp[0][0][m] = 0;
for (int i = 1; i <= n; i ++ )
for (int j = 0; j <= m; j ++ )
for (int k = 0; k <= j; k ++ )
for (int x = k; x <= m; x ++ )
dp[i][j][k] = min(dp[i][j][k], dp[i - 1][j - k][x] + abs(a[i] - j));
for (int j = 0; j <= m; j ++ )
ans = min(ans, dp[n][m][j]);
cout << ans << "\n";
return 0;
}