Educational Codeforces Round 2 覆盤
阿新 • • 發佈:2021-10-13
A. Extract Numbers
有一說一這題挺毒的,乍一看是個垃圾模擬其實要處理的東西還蠻多,而且我還決定了要邊讀入邊處理,再加上 Vim 用的還不熟練,寫著寫著就寫急躁了。因此我總共寫了 17 分鐘,換了兩種寫法才過。
一遍 AC。
#錯誤警示:心態很重要,細節也要想清楚。Think twice, code once.
const int MAXN = 1e5 + 10; char ss[MAXN]; int n; std::vector<std::string> nums; std::vector<std::string> oths; int main() { std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> (ss + 1); n = (int) strlen(ss + 1); std::string s; bool num = false; bool lz = false; bool others = false; for (int i = 1; i <= n; ++i) { if (ss[i] == ',' || ss[i] == ';') { if (s.empty() || !num || others) oths.push_back(s); else nums.push_back(s); s.clear(); num = lz = others = false; } else { s += ss[i]; if (!isdigit(ss[i]) || others) { num = false; others = true; continue; } if (num == false && others == false && isdigit(ss[i])) { num = true; if (ss[i] == '0') lz = true; continue; } if (lz && isdigit(ss[i])) { num = false; others = true; continue; } } } if (s.empty() || !num || others) oths.push_back(s); else nums.push_back(s); s.clear(); num = lz = others = false; if (nums.size() != 0) { cout << "\""; forall (nums, i) { cout << nums[i]; if (i != (int) nums.size() - 1) cout << ','; }cout << "\"" << endl; } else cout << "-" << endl; if (oths.size() != 0) { cout << "\""; forall (oths, i) { cout << oths[i]; if (i != (int) oths.size() - 1) cout << ','; }cout << "\"" << endl; } else cout << "-" << endl; return 0; }
B. Queries about less or equal elements
這題也是有非常嚴重的失誤,最開始已經想到了最簡單的做法:離線後排序 B 陣列然後一個指標掃過去,但是不知道為啥還是決定手寫二分,結果光榮寫掛。瞪了一會未果決定換離散化 + 樹狀陣列,然而還是掛在後面幾個點。
又瞪了一會無果,打算隨機改幾個易錯點,正好發現樹狀陣列的最大長度可以達到二倍的 n,遂把陣列開大兩倍不放心又開個 long long,交一遍過了。但實際上是不用開 long long 的。
#錯誤警示:一定要穩紮穩打考慮好所有細節,比如最大資料範圍到底能有多少,特別是 CP 這種爭分奪秒的比賽欲速一定不達。
const int MAXN = 2e5 + 10; int n, m; lli aa[MAXN], bb[MAXN]; lli nums[MAXN * 2], cnt; struct BIT { lli ss[MAXN * 2]; void mod(int x) { for (; x <= n + m; x += (x & (-x))) ++ss[x]; } int qry(int x) { int r = 0;for (; x; x -= (x & (-x))) r += ss[x]; return r; } } bt; int main() { std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n >> m; rep (i, 1, n) { cin >> aa[i]; nums[++cnt] = aa[i]; } rep (i, 1, m) { cin >> bb[i]; nums[++cnt] = bb[i]; } std::sort(nums + 1, nums + 1 + cnt); cnt = (std::unique(nums + 1, nums + 1 + cnt) - nums - 1); // DEBUG(cnt); for (int i = 1; i <= n; ++i) { aa[i] = (std::lower_bound(nums + 1, nums + 1 + cnt, aa[i]) - nums); bt.mod(aa[i]); // DEBUG(aa[i]); } rep (i, 1, m) bb[i] = (std::lower_bound(nums + 1, nums + 1 + cnt, bb[i]) - nums); rep (i, 1, m) { cout << bt.qry(bb[i]) << ' '; // DEBUG(bb[i]); } cout << endl; return 0; }
C. Make Palindrome
做法很顯然了,就是修改所有出現奇數次的字元。然而我最開始光考慮到字典序最小的要求,於是把所有奇數次字母都找了一個修改成了 'a'
,這個肯定是不符合修改次數最小的條件的,交上去就光榮 WA 了。瞪了一會無果,開始隨機手造資料,結果第一發就把自己 hack 掉了,然後才意識到這個修改次數不是最小的,接著才想到正解。
結果交上去第二發還是 WA 了,發現自己只修改了長度為奇數的情況,偶數是一樣的。然後才過掉了這題。
#錯誤警示:槽點太多不知從何說起,一定不要想當然,好好考慮一下貪心策略是不是對的、需不需要分類討論。
const int MAXN = 2e5 + 10; char ss[MAXN]; int n; int cnt[27]; int main() { std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> (ss + 1); n = (int) strlen(ss + 1); for (int i = 1; i <= n; ++i) { ++cnt[ss[i] - 'a']; } if (n & 1) { // at most one odd std::vector<int> odds; for (int i = 0; i < 26; ++i) { if (cnt[i] & 1) { odds.push_back(i); } } std::reverse(ALL(odds)); for (int i = 0, siz = (int) odds.size(); i < siz / 2; ++i) { --cnt[odds[i]]; ++cnt[odds[odds.size() - 1 - i]]; } int fx = 0; for (int i = 0; i < 26; ++i) { if (cnt[i] & 1) fx = i; for (int j = 1; j <= cnt[i] / 2; ++j) { cout << (char) (i + 'a'); } } cout << (char) (fx + 'a'); for (int i = 25; i >= 0; --i) { for (int j = 1; j <= cnt[i] / 2; ++j) { cout << (char) (i + 'a'); } } } else { // no odd std::vector<int> odds; for (int i = 0; i < 26; ++i) { if (cnt[i] & 1) { odds.push_back(i); } } std::reverse(ALL(odds)); for (int i = 0, siz = (int) odds.size(); i < siz / 2; ++i) { --cnt[odds[i]]; ++cnt[odds[odds.size() - 1 - i]]; } for (int i = 0; i < 26; ++i) { for (int j = 1; j <= cnt[i] / 2; ++j) { cout << (char) (i + 'a'); } } for (int i = 25; i >= 0; --i) { for (int j = 1; j <= cnt[i] / 2; ++j) { cout << (char) (i + 'a'); } } } return 0; }
E. Lomsat gelral
dsu on tree 板子題。後面會寫專題題解。
const int MAXN = 1e5 + 10;
int n, col[MAXN];
std::vector<int> G[MAXN];
int siz[MAXN], heavy[MAXN];
void dfs(int u, int fa) {
siz[u] = 1;
for (auto v : G[u]) {
if (v == fa) continue;
dfs(v, u);
siz[u] += siz[v];
if (siz[v] > siz[heavy[u]]) heavy[u] = v;
}
}
lli cnt[MAXN], mxcnt, thisans, fson;
lli ans[MAXN];
void get(int u, int fa, int x) {
cnt[col[u]] += x;
if (cnt[col[u]] > mxcnt) mxcnt = cnt[col[u]], thisans = col[u];
else if (cnt[col[u]] == mxcnt) thisans += col[u];
for (auto v : G[u]) {
if (v == fa || v == fson) continue;
get(v, u, x);
}
}
void dfs2(int u, int fa, bool del) {
mxcnt = thisans = 0;
for (int v : G[u]) {
if (v == fa) continue;
if (v != heavy[u]) dfs2(v, u, true);
} if (heavy[u]) dfs2(heavy[u], u, false), fson = heavy[u];
get(u, fa, 1); fson = 0;
ans[u] = thisans;
if (del) { get(u, fa, -1); mxcnt = thisans = 0; }
}
int main() {
std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n;
rep (i, 1, n) cin >> col[i];
rep (i, 1, n - 1) {
int u, v; cin >> u >> v;
G[u].push_back(v); G[v].push_back(u);
}
dfs(1, 0);
dfs2(1, 0, true);
rep (i, 1, n) cout << ans[i] << ' ';
cout << endl;
return 0;
}