# TBC 002 Editorial ---- Rank.1 :place_of_worship: **[qq11123334](https://toj.tfcis.org/oj/acct/1749/)** Rank.2 :place_of_worship: **[Zaim](https://toj.tfcis.org/oj/acct/11789/)** Rank.3 :place_of_worship: **[sa072686](https://toj.tfcis.org/oj/acct/849/)** --- ## pA. 又帥又潮的男人 Author : DB0917 首殺 : madfarm0711 ---- 簡單的條件判斷,送分題 複雜度 : $O(n)$ ---- code: ```C++ #include <bits/stdc++.h> using namespace std; using ll = long long; int main() { ios::sync_with_stdio(0); cin.tie(0); int n; cin >> n; vector<int> a(n), b(n); int mxa=0, mxb=0, idxa, idxb; for(int i=0;i<n;i++) { cin >> a[i]; if(a[i]>mxa) { mxa=a[i]; idxa=i; } } for(int i=0;i<n;i++) { cin >> b[i]; if(b[i]>mxb) { mxb=b[i]; idxb=i; } } if(idxa==idxb) cout << idxa+1 << '\n'; else cout << -1 << '\n'; } ``` ---- ### Fun Fact: 這題本來要叫做 "又高又潮的人" 但想了一下覺得聽起來太怪了,就改了 --- ## pB. 帥潮寫數學 Author : DB0917 首殺 : ghostapplemonkey ---- 假設 $x+y=A_i$ 且 $y-x=A_j$ ($1\le i, j \le n$) 那麼你可以發現: 如果 $x$ 和 $y$ 要有解, $\frac{A_i + A_j}{2}$ 必須要是整數 因此答案為 : $\frac{oddcnt \times (oddcnt + 1)}{2} + \frac{evencnt \times (evencnt + 1)}{2}$ ##### \* $oddcnt$ 是奇數出現個數,$evencnt$ 是偶數出現個數 複雜度 : $O(n)$ ---- code: ```C++ #include <bits/stdc++.h> using namespace std; using ll = long long; #define int ll signed main() { ios::sync_with_stdio(0); cin.tie(0); int oc=0, ec=0, n, tmp; cin >> n; while(n--) { cin >> tmp; if(tmp%2) oc++; else ec++; } cout << (oc+1LL)*oc/2LL + (ec+1LL)*ec/2LL << '\n'; } ``` ---- ### Fun Fact: 這題pdf少打了一個條件,就是$x$跟$y$要是整數 ~~但是我覺得這個大家都應該要知道吧~~ --- ## pC. PIZZA MOZZARELLA Author : DB0917 首殺 : sa072686 ---- 仔細觀察後可以發現,題目等同於在問你: 要怎麼排序才能盡可能的不要出現連續相同數字? 觀察到這個性質後 就可以利用貪心演算法解決這題了 複雜度 : $O(n+m)$ ---- code: ```C++ #include <bits/stdc++.h> using namespace std; using ll = long long; #define int ll signed main() { cin.tie(0); ios::sync_with_stdio(0); int n, m, sum=0; cin >> n >> m; vector<int> cnt(m+1, 0); for(int i=0;i<n;i++) { int tmp; cin >> tmp; cnt[tmp]++; } for(int i=1;i<=m;i++) { int tmp; cin >> tmp; sum+=tmp*cnt[i]; } int mxo=(max_element(cnt.begin(), cnt.end())-cnt.begin()), val=cnt[mxo]; if(val<=n-val+1) cout << sum << '\n'; else { int basic=n-val+1, times=(val-basic)/basic, left=(val-basic)%basic; cout << sum+(1+times)*times/2*basic+(times+1)*left << '\n'; } } ``` ---- ### Fun Fact: 這題的題序 (自我介紹) 真的是我們庶務本人寫的 --- ## pD. 噴棋 Author : Blameazu. 首殺 : sa072686 ---- 觀察到,棋子一去不復返,一個點最多走一遍 根本就是DP水題 但是數學好難,我不會 看你要用外積還是畢氏定理硬幹都可以 複雜度 : $O(n^3)$ ---- code (by Blameazu.): ```C++ #include <bits/stdc++.h> using namespace std; #pragma GCC optimize("Ofast") #define ll long long #define int ll #define pii pair<int, int> int dp[505]; signed main() { ios::sync_with_stdio(false), cin.tie(0); int n; cin >> n; vector<pii> v(n+1); auto dis = [&](const auto &AA, const auto &BB) -> int { const auto A = v[AA]; const auto B = v[BB]; const auto &[a, b] = A; const auto &[c, d] = B; return (a-c)*(a-c) + (b-d)*(b-d); }; for(int i = 1; i <= n; i++) { cin >> v[i].first >> v[i].second; } for(int i = 1; i <= n; i++) dp[i] = INT_MIN; dp[1] = 0; int ans = 0; for(int i = 1; i <= n; i++) { for(int j = i+1; j <= n; j++) { for(int k = j+1; k <= n; k++) { if(dis(i, j) < dis(k,j) && dis(k, j) < dis(i, k)) { pii A = {v[j].first - v[i].first, v[j].second - v[i].second}; pii B = {v[j].first - v[k].first, v[j].second - v[k].second}; if(A.first * B.second - B.first * A.second == 0 && A.first * B.first + A.second * B.second < 0) { dp[k] = max(dp[k], dp[i] + 1); } } } } ans = max(ans, dp[i]); } cout << ans << '\n'; } ``` ---- code (by DB0917): ```C++ #include <bits/stdc++.h> using namespace std; using ll = long long; #define int ll signed main() { ios::sync_with_stdio(0); cin.tie(0); int n; cin >> n; vector<pair<int, int>> vp(n); vector<int> dp(n, INT_MIN); dp[0] = 0; for(auto& [l, r] : vp) cin >> l >> r; for(int j=2;j<n;j++) { for(int i=0;i<j-1;i++) { for(int k=i+1;k<j;k++) { int dx1=vp[k].first-vp[i].first, dx2=vp[j].first-vp[k].first, dy1=vp[k].second-vp[i].second, dy2=vp[j].second-vp[k].second; int dx3=vp[j].first-vp[i].first, dy3=vp[j].second-vp[i].second; bool xs=((dx1>=0 && dx2>=0) || (dx1<=0 && dx2<=0)), ys=((dy1>=0 && dy2>=0) || (dy1<=0 && dy2<=0)); if(xs && ys && (dx1*dy2==dx2*dy1) && dx1*dx1+dy1*dy1<dx2*dx2+dy2*dy2 && dx2*dx2+dy2*dy2<dx3*dx3+dy3*dy3) { dp[j]=max(dp[j], dp[i]+1); } } } } cout << *max_element(dp.begin(), dp.end()); return 0; } ``` ---- ## Fun Fact: 這題為什麼要用賽中HACK制呢 ###### 因為測資生不完了QQ --- ## pE. 礙立斯和爆駁 Author : shorya1835 首殺 : ghostapplemonkey ---- 觀察一下,發現... 唉呦我的媽,Bob根本就是被霸凌 Bob試圖交換的數對Alice下回合必定能復原 而且還會額外加cost,太可憐了吧 ---- 因此對Bob來說最好的操作就是直接結束遊戲! 那麼對於Alice來說她只要選擇結束遊戲或交換即可 這邊暴力掃過去! 複雜度 : $O(n)$ ---- code: ```C++ #include <bits/stdc++.h> using namespace std; template<typename T> using vc = vector<T>; template<typename T> using vvc = vector<vector<T>>; template<typename T> using maxheap = priority_queue<T>; template<typename T> using minheap = priority_queue<T, vector<T>, greater<T>>; using ll = long long; #pragma GCC optimize("Ofast") int main() { ios::sync_with_stdio(0); cin.tie(0); int t; t=1; while(t--) { int n; cin >> n; vc<ll> v(n); ll as=0, bs=0; for(int i=0;i<n;i++) { cin >> v[i]; if(!(i%2)) as+=v[i]; else bs+=v[i]; } ll me = LLONG_MAX, best1 = LLONG_MIN, mo = LLONG_MAX, best2 = LLONG_MIN; for(int i=0;i<n;i++) { if(!(i%2)) { me = min(me, 2*v[i]+i); if(mo != LLONG_MAX) best2 = max(best2, (-2*v[i]+i)-mo); } else { mo = min(mo, -2*v[i]+i); if(me != LLONG_MAX) best1 = max(best1, (2*v[i]+i)-me); } } ll mx = (n%2?n:n-1)-1; mx=max(mx, best1); mx=max(mx, best2); cout << as-bs+mx << '\n'; } } ``` ---- ## Fun Fact: https://codeforces.com/contest/2140/problem/C --- ## pF. 樹上背包問題 Author : DB0917 ---- 大資結,經典的在線求區間最大和 + HLD 裸題,但是在合併區塊的時候要注意 複雜度 : $O(n+q \log ^2 n)$ ---- code: ```C++ #include <bits/stdc++.h> using namespace std; using ll = long long; #define int ll const int MAXN=1000010; const ll NEG = LLONG_MIN/4; struct node { int dp[2][2]={}; bool empty; node() { empty = true; dp[0][0] = dp[0][1] = dp[1][0] = dp[1][1] = NEG; } node(int x) { empty=false; dp[0][0]=NEG; dp[1][0]=dp[0][1]=dp[1][1]=x; } int answer() const { if (empty) return NEG; return max({dp[0][0], dp[0][1], dp[1][0], dp[1][1]}); } node operator+(const node& other) const { if(other.empty) return *this; else if(empty) return other; node res; res.empty=false; res.dp[0][0]=max({answer(), other.answer(), dp[0][1]+other.dp[1][0]}); res.dp[0][1]=max(other.dp[0][1], dp[0][1]+other.dp[1][1]); res.dp[1][0]=max(dp[1][0], dp[1][1]+other.dp[1][0]); res.dp[1][1]=dp[1][1]+other.dp[1][1]; return res; } }; int parent[MAXN], depth[MAXN], heavy[MAXN], sz[MAXN], head[MAXN], pos[MAXN], tmp[MAXN], val[MAXN], cur_pos=0; node seg[MAXN*4]; vector<vector<int>> G(MAXN); int dfs(int now) { sz[now]=1; int mx=0; for(auto& next : G[now]) { if(next==parent[now]) continue; parent[next]=now; depth[next]=depth[now]+1; int s=dfs(next); sz[now]+=s; if(s>mx) { mx=s; heavy[now]=next; } } return sz[now]; } void decompose(int now, int top) { head[now]=top; pos[now]=++cur_pos; if(heavy[now]) decompose(heavy[now], top); for(auto& next : G[now]) { if(next==parent[now] || next==heavy[now]) continue; decompose(next, next); } } void build(int l, int r, int idx) { if(l==r) { seg[idx]=node(val[l]); return; } int mid=(l+r)>>1; build(l, mid, idx<<1); build(mid+1, r, idx<<1|1); seg[idx]=seg[idx<<1]+seg[idx<<1|1]; } void update(int l, int r, int p, int idx, int v) { if(l>p || r<p) return; if(l==r) { seg[idx]=node(v); return; } int mid=(l+r)>>1; if(mid>=p) update(l, mid, p, idx<<1, v); if(mid+1<=p) update(mid+1, r, p, idx<<1|1, v); seg[idx]=seg[idx<<1]+seg[idx<<1|1]; } node query(int nl, int nr, int gl, int gr, int idx) { if(nl>gr || nr<gl) return node(); if(nl>=gl && nr<=gr) return seg[idx]; int mid=(nl+nr)>>1; return query(nl, mid, gl, gr, idx<<1)+query(mid+1, nr, gl, gr, idx<<1|1); } node rev_node(const node &a) { if(a.empty) return a; node b; b.empty = false; b.dp[1][1] = a.dp[1][1]; b.dp[1][0] = a.dp[0][1]; b.dp[0][1] = a.dp[1][0]; b.dp[0][0] = a.dp[0][0]; return b; } int QueryPath(int u, int v, int n) { bool left_has = false, right_has = false; node left_node, right_node; while (head[u] != head[v]) { if (depth[head[u]] >= depth[head[v]]) { node cur = query(1, n, pos[head[u]], pos[u], 1); node cur_rev = rev_node(cur); if (!left_has) left_node=cur_rev, left_has=true; else left_node = left_node + cur_rev; u = parent[head[u]]; } else { node cur = query(1, n, pos[head[v]], pos[v], 1); if (!right_has) right_node = cur, right_has=true; else right_node = cur + right_node; v = parent[head[v]]; } } node mid; if (pos[u] <= pos[v]) mid = query(1, n, pos[u], pos[v], 1); else mid = rev_node(query(1, n, pos[v], pos[u], 1)); node res = mid; if (left_has) res = left_node+res; if (right_has) res = res+right_node; return res.answer(); } signed main() { cin.tie(0); ios::sync_with_stdio(0); int n, q; cin >> n >> q; for(int i=1;i<=n;i++) cin >> tmp[i]; for(int i=1;i<n;i++) { int a, b; cin >> a >> b; G[a].push_back(b); G[b].push_back(a); } dfs(1); decompose(1, 1); for(int i=1;i<=n;i++) val[pos[i]]=tmp[i]; build(1, n, 1); while(q--) { int cmd, u, v; cin >> cmd >> u >> v; if(cmd==1) { int ans=QueryPath(u, v, n); if(ans<0) cout << "BURST\n"; else cout << ans << '\n'; } else { update(1, n, pos[u], 1, v); } } } ``` ---- ## Fun Fact: 這題一點都不Fun --- ## 賽中 & 賽後 ---- ![image](https://hackmd.io/_uploads/r1AMeaJk-x.png) 為什麼沒有人要撈部分分? ---- ![image](https://hackmd.io/_uploads/Bk2dxpk1-x.png) 貪心題用線段樹過了... orz ---- ![image](https://hackmd.io/_uploads/BkqMZ6kkZx.png) 不要用AI阿... ---- [補題連結](https://toj.tfcis.org/oj/proset/?&order=None&show=all&proclass_id=198) [Feedback](https://forms.gle/koZETxySaTMsSQV98)
{"title":"TBC 002 Editorial","contributors":"[{\"id\":\"8ef74834-8c0e-4ca4-a3d6-02428329176f\",\"add\":10703,\"del\":27,\"latestUpdatedAt\":1761755767276}]","description":"Rank.1 :place_of_worship:qq11123334"}
    146 views