【C++】競程筆記(枚舉習題練習)
- https://zerojudge.tw/ShowProblem?problemid=c435
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include <bits/stdc++.h> using namespace std;
int main() { ios_base::sync_with_stdio(false); cin.tie(NULL);
int n; cin >> n; vector<int> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; }
int max_left = a[0]; int ans = INT_MIN; for (int j = 1; j < n; j++) { ans = max(ans, max_left - a[j]); max_left = max(max_left, a[j]); }
cout << ans << endl; return 0; }
|
找最大差值。 a[i]−a[j] ,但 i<j 。
解題思路:定義一個變數 max_left = a[0],然後用他去紀錄當前位置 j 左邊的最大值(即 a[0] 到 a[j−1] 的最大值),而對於每個 j ,計算 max_left - a[j] 的最大值。
而變數 ans 則是用來記錄所有計算出的 max_left - a[j] 的最大值。
處理完當前的 j 後,將 max_left 指定為 max(max_left, a[j]),以繼續用於下一個位置 j+1 。
最後的時間複雜度為 O(n) 。
大致上有三種情況要去考慮:
遞減數列: {5,4,3,2,1} ,最大差值就是 a[0]−a[4]=4 。
遞增數列: {1,2,3,4,5} :
- j = 1, 1 - 2 = -1, ans = -1, max_left = 2
- …
- j = 4, 4 - 5 = -1, ans = -1
- 最終 ans = -1, 所以最大差值就 -1。
相同元素的數列: {10000,10000,10000} :
- j = 1, 10000 - 10000 = 0, ans = 0
- j = 2, 10000 - 10000 = 0, ans = 0
- 最終 ans = 0, 所以最大差值 = 0。
- https://codeforces.com/problemset/problem/1352/E
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| #include <bits/stdc++.h> using namespace std;
int main() { ios::sync_with_stdio(false); cin.tie(0);
int t; cin >> t; for (int test = 0; test < t; test++) { int n; cin >> n; vector<int> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } vector<long long> prefix(n + 1, 0); for (int i = 1; i <= n; i++) { prefix[i] = prefix[i - 1] + a[i - 1]; } vector<bool> achievable(n + 1, false); for (int i = 0; i < n - 1; i++) { for (int j = i + 1; j < n; j++) { long long sum = prefix[j + 1] - prefix[i]; if (sum > n) break; achievable[sum] = true; } } int count = 0; for (int i = 0; i < n; i++) { if (achievable[a[i]]) { count++; } } cout << count << "\n"; } return 0; }
|
題目大意:
給定一個序列 a1,a2,⋯,an ,若有一個長度至少為 2 的區間總和 al+al+1+⋯+ar=ai ,則 ai 是 special element。求序列內有幾個 special elements。
解題思路:
首先可能會想到要直接枚舉所有可能的子陣列(從索引 i 到 j,其中 j≥i+1 )並計算其和,時間複雜度為 O(n3) (枚舉起點 O(n) 、終點 O(n) 、計算和 O(n) ),因為題目限制 n≤8000 ,這樣會太慢。
所以可以使用 Prefix sum,前綴和去求區間和,那個 sum 就是在用前綴和求區間和了。
判斷式 if (sum > n) break; 是優化算法,如果總和加一加超過陣列長度的話,那基本上可以不用再檢查了,就直接 break。
最後是看 achievable 的布林值情況,如果 true 就計數,這邊 O(n) 。
備註:後面的題目不知道為什麼 NTUCPC Guide 的連結打不開,所以就先這樣。喔對了,OwO 學長那題我解不出來,所以放棄 orz,link:https://zerojudge.tw/ShowProblem?problemid=c412