## Spring Practices 06 心得&題解 [<<回主頁](https://hackmd.io/@r1cky/Sk2hKzga6) ### 前言 因為是學校練習用的,不知道題目能不能公開,但還是寫個心得好了。 今天在家 vir QQ 總共有五題,編號 A~E AC 順序 : ABCE(D) D 賽後補的。 ### pA 枚舉分割起點,每次就暴力掃過一次(其實可以前綴和壓掉一個 $N$,但本題不需要),時間複雜度 $\Theta(N^2)$。 ```cpp= // Author : rickytsung // Problem : // Date : #pragma GCC optimize("O3,unroll-loops") #pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt") #include <bits/stdc++.h> #define i64 long long #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define pii pair<int, int> #define f first #define s second #define pb(x) push_back(x) using namespace std; mt19937 rng(114514); int rnd(int l, int r) { return uniform_int_distribution<int>(l, r)(rng); } i64 gcd(i64 a,i64 b){ if (a%b == 0) return(b); else return(gcd(b, a%b)); } i64 lcm(i64 a, i64 b){ return a/gcd(a, b) * b; } int main() { IOS; int n; string s; cin >> n >> s; for(int i = 1; i < n; i++){ int o1 = 0, l1 = 0, o2 = 0, l2 = 0; for(int j = 0; j < i; j++){ if(s[j] == 'O'){ o1++; } else{ l1++; } } for(int j = i ; j < n; j++){ if(s[j] == 'O'){ o2++; } else{ l2++; } } if(o1 != o2 && l1 != l2){ cout << i; return 0; } } cout << -1; return 0; } ``` ### pB 構造,讓 $b_i = N - a_i$ 可以製造最大值。 ``` cpp= // Author : rickytsung // Problem : // Date : #pragma GCC optimize("O3,unroll-loops") #pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt") #include <bits/stdc++.h> #define i64 long long #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define pii pair<int, int> #define f first #define s second #define pb(x) push_back(x) using namespace std; mt19937 rng(114514); const int mod1 = 998244353; int rnd(int l, int r) { return uniform_int_distribution<int>(l, r)(rng); } i64 gcd(i64 a,i64 b){ if (a%b == 0) return(b); else return(gcd(b, a%b)); } i64 lcm(i64 a, i64 b){ return a/gcd(a, b) * b; } int main() { IOS; int n, x; cin >> n; for(int i = 0; i < n; i++){ cin >> x; cout << n + 1 - x << ' '; } return 0; } ``` ### pC 注意到,如果在 $p$ 中 $j$ 在 $i$ 後面,則 $i$ 一定不能是 $j$ 的子孫。 如果答案存在,我們試著使最終 $dist_i = i,i \neq root$。 也就是加入時檢查父節點的 $dist_{f}$ 是否有被跑過,有的話構造 $cost = i - dist_{f}$,這時滿足 $dist_i = i$。 ```cpp= #pragma GCC optimize("O3,unroll-loops") #pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt") #include <bits/stdc++.h> #define i64 long long #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define pii pair<int, int> #define f first #define s second #define pb(x) push_back(x) using namespace std; mt19937 rng(114514); const int mod1 = 998244353; int rnd(int l, int r) { return uniform_int_distribution<int>(l, r)(rng); } i64 gcd(i64 a,i64 b){ if (a%b == 0) return(b); else return(gcd(b, a%b)); } i64 lcm(i64 a, i64 b){ return a/gcd(a, b) * b; } int main() { IOS; int t, n, x; cin >> t; while(t--){ cin >> n; int f[n+1], p[n+1], ans[n+1] = {0}, cost[n+1]; int ok = 1; for(int i = 1; i <= n; i++){ cin >> f[i]; } for(int i = 1; i <= n; i++){ cin >> p[i]; cost[i] = -1; } if(f[p[1]] != p[1]){ ok = 0; } else{ cost[p[1]] = 0; } for(int i = 2; i <= n; i++){ if(cost[f[p[i]]] < 0){ ok = 0; continue; } else{ cost[p[i]] = i; ans[p[i]] = i - cost[f[p[i]]]; } } if(!ok){ cout << -1 << '\n'; } else{ for(int i = 1; i <= n; i++){ cout << ans[i] << ' '; } cout << '\n'; } } } ``` ### pD 首先,樹要存在的必要條件是 $a = c-1$,因為 $a$ 影響的是分支數,會一路分到最底,也就是 $c$。 接著,我們盡量把 $2$ 放在上面,這樣可以最小化點,假設 $2$ 放了 $l$ 層,還剩下 $t$ 個空位,則先放入 $b, c$ 的點 (順序其實到最後沒差),然後如果放不完,答案會是 $l + \lceil \frac{b+c-t}{t + 2(2^{l-1} - t)}\rceil$ ,放的完就剛好是 $l$。 ```cpp= // Author : rickytsung // Problem : // Date : #pragma GCC optimize("O3,unroll-loops") #pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt") #include <bits/stdc++.h> #define i64 long long #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define pii pair<int, int> #define f first #define s second #define pb(x) push_back(x) using namespace std; mt19937 rng(114514); const int mod1 = 998244353; int rnd(int l, int r) { return uniform_int_distribution<int>(l, r)(rng); } i64 gcd(i64 a,i64 b){ if (a%b == 0) return(b); else return(gcd(b, a%b)); } i64 lcm(i64 a, i64 b){ return a/gcd(a, b) * b; }; int main() { int t; cin >> t; while(t--){ int a, b, c, l = 1, p = 1; int ok = 1, ans = 0; cin >> a >> b >> c; int bc = b + c; if(c - a != 1) ok = 0; while(a > p){ l ++; a -= p; p <<= 1; } int last = p - a; //cout << l << ' ' << a << ' ' << p ; if(bc <= last){ ans = l; } else{ bc -= last; ans = l + (bc - 1)/(2 * a + last) + 1; } if(!ok){ cout << -1; } else{ cout << ans - 1; } cout << '\n'; } } ``` ### pE 暴力實作,然後可以把字串根據字典序轉成獨一無二的數字,會比較好做。 ```cpp= / Author : rickytsung // Problem : // Date : #pragma GCC optimize("O3,unroll-loops") #pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt") #include <bits/stdc++.h> #define i64 long long #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define pii pair<int, int> #define f first #define s second #define pb(x) push_back(x) using namespace std; mt19937 rng(114514); const int mod1 = 998244353; int rnd(int l, int r) { return uniform_int_distribution<int>(l, r)(rng); } i64 gcd(i64 a,i64 b){ if (a%b == 0) return(b); else return(gcd(b, a%b)); } i64 lcm(i64 a, i64 b){ return a/gcd(a, b) * b; } vector<vector<int>> mp (3); bool vis[3][3]; int ans = 48763; void walk(int x, int y, int cur, int now){ if(vis[x][y]) return; if(x < 0 || y < 0 || y > 2 || x > 2) return; vis[x][y] = 1; int base = 1; for(int i = 0; i < 2 - cur; i++){ base *= 3; } now += base * mp[x][y]; if(cur == 2){ ans = min(ans, now); vis[x][y] = 0; return; } for(int i = -1; i < 2; i++){ for(int j = -1; j < 2; j++){ if(i == 0 && j == 0) continue; walk(x+i, y+j, cur+1, now); } } vis[x][y] = 0; } int main() { IOS; string s; for(int i = 0 ; i < 3; i++){ cin >> s; for(int j = 0; j < 3; j++){ mp[i].pb(s[j]-'A'); } } for(int i = 0 ; i < 3 ; i++){ for(int j = 0; j < 3; j++){ walk(i, j, 0, 0); } } cout << (char)(ans/9 + 'A'); cout << (char)((ans/3) % 3 + 'A'); cout << (char)(ans%3 + 'A'); } ```