AtCoder Beginner Contest 222 覆盤
阿新 • • 發佈:2021-10-13
A. Four Digits
一遍 AC。
int n;
int main() {
scanf("%d", &n);
std::string str = std::to_string(n);
while (str.size() != 4) str = '0' + str;
printf("%s\n", str.c_str());
return 0;
}
B. Failing Grade
一遍 AC。
int n, p; int main() { std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n >> p; int ans = 0; rep (i, 1, n) { int x; cin >> x; ans += (x < p); } cout << ans << endl; return 0; }
C. Swiss-System Tournament
機房裡吵得讀不下去題,拖到後面才做的。
WA 了 1 發,先是讀錯題,然後又打了好幾個 typo。
#錯誤警示:拒絕打錯微小字元,比如 i
和 j
。
#錯誤警示:讀好題目的資料範圍資訊,比如 \(2n\) 個人需要開兩倍陣列。
const int MAXN = 50 + 10; const int MAXM = 100 + 10; int judge(int id1, char s1, int id2, char s2) { if (s1 == s2) return 2; if (s1 == 'G') return s2 == 'C'; if (s1 == 'C') return s2 == 'P'; /* s1 == 'P' */ return s2 == 'G'; } int n, m; char give[MAXN * 2][MAXM]; int rank[MAXN * 2]; // do not forget struct ND { int val, id; } wins[MAXN * 2]; bool cmp(ND x, ND y) { return x.val == y.val ? x.id < y.id : x.val > y.val; } bool cmp2(ND x, ND y) { return x.id < y.id; } int main() { std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n >> m; rep (i, 1, 2 * n) { cin >> (give[i] + 1); rank[i] = i; wins[i].id = i; } rep (i, 1, m) { // typo: i -> j std::sort(wins + 1, wins + 1 + 2 * n, cmp2); rep (j, 1, n) { int s1 = rank[j * 2 - 1], s2 = rank[j * 2]; if (judge(s1, give[s1][i], s2, give[s2][i]) == 2) continue; if (judge(s1, give[s1][i], s2, give[s2][i])) ++wins[s1].val; else ++wins[s2].val; } std::sort(wins + 1, wins + 1 + 2 * n, cmp); rep (j, 1, 2 * n) rank[j] = wins[j].id; // rep (x, 1, 2 * n) cout << rank[x] << ' '; // cout << endl; } rep (i, 1, 2 * n) cout << rank[i] << endl; return 0; }
D. Between Two Arrays
設 f[i][j]
表示考慮前 i 個限制,第 i 次選的數是 j 的方案數。搞一個字首和優化轉移即可。
一遍 AC。
const int MAXN = 3000 + 10; const int MAXS = 3000; const int HA = 998244353; int n, aa[MAXN], bb[MAXN]; int dp[MAXN][MAXN]; lli sumdp[MAXN][MAXN]; // sum of dp[i][1~j] int main() { std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n; rep (i, 1, n) cin >> aa[i]; rep (i, 1, n) cin >> bb[i]; rep (i, 1, 1) { rep (x, aa[i], bb[i]) dp[i][x] = 1; rep (x, aa[i], MAXS) (sumdp[i][x] = sumdp[i][x - 1] + dp[i][x]) %= HA; } rep (i, 2, n) { rep (j, aa[i], bb[i]) { dp[i][j] = sumdp[i - 1][j]; } rep (j, aa[i], MAXS) (sumdp[i][j] = sumdp[i][j - 1] + dp[i][j]) %= HA; } cout << sumdp[n][bb[n]] << endl; return 0; }
E. Red and Blue Tree
首先可以算出每條邊被經過的次數 \(c_i\),然後就可以 DP 了。
最開始想的是 f[i][j]
表示前 \(i\) 條邊,\(R - B = j\) 的方案數,但是時空複雜度是 \(O(N|K|)\) 的,可不可以滾動陣列沒試過,總覺得應該過不去就沒寫。
題解又做了一步轉化:設 \(S = \sum c_i\),於是題目轉化成了選擇一些 \(c_i\) 求和得到 \(\frac{S + K}{2}\) 的方案數(\(S + K < 0\) 或是偶數的情況即是無解)。這就是一個揹包板子了。
時間複雜度還是 \(O(N|K|)\) 居然能過 離譜。
const int MAXN = 1000 + 10;
const int MAXM = 100000 + 10;
const int HA = 998244353;
int n, m, k;
struct E { int v, id; };
std::vector<E> G[MAXN];
int cnt[MAXN];
int dp[MAXM];
bool dfs(int u, int fa, int end) {
if (u == end) return true;
bool ans = false;
forall (G[u], i) {
int v = G[u][i].v, id = G[u][i].id;
if (v == fa) continue;
if (dfs(v, u, end)) {++cnt[id]; ans = true;}
} return ans;
}
int main() {
std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n >> m >> k;
std::vector<int> vc;
rep (i, 1, m) { int x; cin >> x; vc.push_back(x); }
rep (i, 1, n - 1) {
int u, v; cin >> u >> v;
G[u].push_back({v, i}); G[v].push_back({u, i});
}
rep (i, 1, m - 1) {
dfs(vc[i - 1], 0, vc[i]);
}
int S = 0;
rep (i, 1, n - 1) {
S += cnt[i];
}
if ((S + k) < 0 || ((S + k) & 1)) {
cout << 0 << endl; return 0;
}
dp[0] = 1;
for (int i = 1; i <= n - 1; ++i) {
for (int j = MAXM - 10; j >= cnt[i]; --j) {
(dp[j] += dp[j - cnt[i]]) %= HA;
}
} cout << dp[(S + k) >> 1] << endl;
return 0;
}
F. Expensive Expense
樹的直徑端點。
後悔考場上沒開這題。
交了好幾發沒過,一查發現是 dis
和 dist
寫 typo 了。
#錯誤警示:寫程式碼專注一點,不要純靠肌肉記憶,因為你肌肉記憶的和這題可能有些出入。
const int MAXN = 200000 + 10;
int n;
lli val[MAXN];
struct E { int v; lli val; }; std::vector<E> G[MAXN];
bool operator < (const E &x, const E &y) {
return x.val > y.val;
}
lli dist[MAXN];
void sp(int st, lli *dis) {
for (int i = 1; i <= n; ++i) dis[i] = (1ll << 62);
std::priority_queue<E> q;
static bool vis[MAXN]; memset(vis, 0, sizeof vis);
q.push({st, dis[st] = 0});
while (!q.empty()) {
int u = q.top().v; q.pop();
if (vis[u]) continue;
vis[u] = true;
forall (G[u], i) {
int v = G[u][i].v, w = G[u][i].val;
// typo: dist dis
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
q.push({v, dis[v]});
}
}
}
}
int main() {
std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n;
rep (i, 1, n - 1) {
int u, v, w; cin >> u >> v >> w;
G[u].push_back({v, w}); G[v].push_back({u, w});
}
rep (i, 1, n) cin >> val[i];
int s1 = 0;
sp(1, dist);
for (int i = 1; i <= n; ++i) {
if (dist[s1] + val[s1] < dist[i] + val[i]) {
s1 = i;
}
}
sp(s1, dist);
int s2 = 0;
for (int i = 1; i <= n; ++i) {
if (s1 == i) continue;
if (dist[s2] + val[s2] < dist[i] + val[i]) {
s2 = i;
}
}
// DEBUG(s1); DEBUG(s2);
static lli dist2[MAXN];
sp(s2, dist2);
for (int i = 1; i <= n; ++i) {
// DEBUG(dist[i]); DEBUG(dist2[i]);
if (i == s1) cout << dist[s2] + val[s2] << endl;
else if (i == s2) cout << dist2[s1] + val[s1] << endl;
else {
if (dist2[i] + val[s2] > dist[i] + val[s1]) cout << dist2[i] + val[s2] << endl;
else cout << dist[i] + val[s1] << endl;
}
}
return 0;
}