## Spring Practices 04 心得&題解 [<<回主頁](https://hackmd.io/@r1cky/Sk2hKzga6) ### 前言 因為是學校練習用的,不知道題目能不能公開,但還是寫個心得好了。 總共有五題,編號 A~E,以下照 AC 順序: ### pA 這題想成位元運算就好,弄到最低 bit 不是 1 就結束。 ```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 i128 __int128 #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; int main() { IOS; int n, ans = 0; cin >> n; while(!(n&1)){ n >>= 1; ans++; } cout << ans << '\n'; } ``` ### pB 我用 int128 做,就不用怕 overflow,如果超過 $10^{18}$ 就立刻歸零,要注意的是要找裡面有沒有 0。 有另個方法是取 log,去估看看他會不會 $10^{18}$,超過就可以不要算。 ```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 i128 __int128 #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; //i128 io template inline void read(i128 &n){ i128 x = 0,f = 1; char ch = getchar(); while(ch < '0'||ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch>='0'&&ch<='9'){ x = (x<<1)+(x<<3)+(ch^48); ch = getchar(); } n = x * f; } inline void print(i128 n){ if(n<0){ putchar('-'); n*=-1; } if(n>9) print(n/10); putchar(n % 10 + '0'); } int main() { IOS; bool cero = 0; int n; i64 in; i128 now = 1; cin >> n; while(n--){ cin >> in; now *= in; if(now > (i128)1e18){ now = 0; } if(in == 0) cero = 1; } if(!cero && !now) now = -1; print(now); } ``` ### pC 排序陣列,用雙指針找,當左指標右移的時候,因為往右數值單調遞增,右指標一定是適當的往左調整(找更小的數),時間複雜度 $O(n)$,要注意不能找重複的。 ```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 i128 __int128 #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; int main() { IOS; int n, a, x; cin >> n >> a; pii s[n]; for(int i = 0; i < n; i++){ cin >> x; s[i] = make_pair(x, i); } sort(s, s+n, cmp); for(int i = 0, ptr = n-1; i < n; i++){ while(ptr != 0 && (s[i].f + s[ptr].f > a || ptr == i)) ptr--; if(s[i].f + s[ptr].f == a && ptr != i){ cout << s[i].s+1 << ' ' << s[ptr].s+1 << '\n'; return 0; } } cout << "IMPOSSIBLE\n"; return 0; } ``` ### pD 首先先離散化重新編號,把 $a_i \rightarrow b_i$,其中 $1 \le b_i \le n$,造出序列 $b(x)$。 定義一個序列 $c(x)$ ,如果現在 sliding window 裡有 $x$,則 $c(x) = 1$,否則 $c(x) = 0$。 維護一個 BIT (Binary Indexed Tree),維護一個對於陣列 $c(x)$ $1 \sim n$ 項的前綴和 $p(x)$,也就是 $p(i) = \sum_{k=1}^i c_k$,並且能 $O(log\ n)$ 做加值操作。 最後,在這上面二分搜即可,找到 $c_i$ 前綴有一半大小的最小值 $m$ ,也就是最小的 $m$ 滿足 $p(m) \ge \lceil k/2 \rceil$ 再轉回 $a_i$ 的值就行。 時間複雜度 $O(n\ log^2\ n)$。 ```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 i128 __int128 #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; // binary indexed tree const int maxn = 2e5+5; i64 bit[maxn]; void update(i64* a, int x, int v){ for(int i = x; i < maxn; i += (i&(-i))){ a[i] += v; } } i64 query(i64* a,int x){ i64 cnt = 0; for(int i = x; i > 0; i -= (i&(-i))){ cnt += a[i]; } return cnt; } int main() { IOS; int n, k, x; cin >> n >> k; pii s[n]; int u[n], v[n+1]; for(int i = 0; i < n; i++){ cin >> x; s[i] = make_pair(x, i); } sort(s, s+n, cmp); for(int i = 0; i < n; i++){ u[s[i].s] = i + 1; v[i + 1] = s[i].f; } for(int i = 0; i < k-1; i++){ update(bit, u[i], 1); } for(int i = k-1; i < n; i++){ update(bit, u[i], 1); if(i >= k) update(bit, u[i-k], -1); int l = 1, r = n; int tar = (k+1) / 2; while(l != r){ int mid = (l + r) / 2; if(query(bit, mid) >= tar){ r = mid; } else{ l = mid+1; } } cout << v[l] << ' '; } } ``` ### pE priority queue 嗷嗷待補 ```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 i128 __int128 #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; int main() { IOS; int n, x; i64 ans = 0, a, b; while(1){ cin >> n; ans = 0; if(!n) return 0; priority_queue <int, vector<int>, greater<int>> pq; for(int i = 0; i < n; i++){ cin >> x; pq.push(x); } while(pq.size() > 1){ a = pq.top(); pq.pop(); b = pq.top(); pq.pop(); ans += a + b; pq.push(a + b); } cout << ans << '\n'; } } ```