# Ten Point Round #8 (Div. 2) 題解 希望大家喜歡這場比賽 OuO ## pA 採買任務 **Prepared by Colten** CBD 身上會有 $c$ 元,買菜總共會花掉 $ae + bf$ 元。 那麼當 $c - ( ae + bd) < 0$ 時,代表 CBD 身上的錢不足以採買所需的蔬菜,輸出 $-1$。 反之,如果有剩下的錢,那麼 CBD 能買的冰淇淋數量為 $\frac{c-(ae+bd)}{d}$。 :::spoiler 參考解答 (C++) ```cpp= #include <bits/stdc++.h> #define int long long using namespace std; signed main(void) { ios_base::sync_with_stdio(false); cin.tie(0); int a,b,c,d; cin >> a >> b >> c >> d; int e,f; cin >> e >> f; if( a * e + b * f > c ) { cout << -1 << "\n"; exit(0); } else { int l = c - ( a * e + b * f ); cout << l / d << "\n"; } return 0; } ``` ::: ## pB 重複的話語 **Prepared by Colten** 讓大家練習迴圈使用的題目 >< :::spoiler 參考解答 (C++) ```cpp= #include <bits/stdc++.h> #define int long long using namespace std; signed main(void) { ios_base::sync_with_stdio(false); cin.tie(0); int q; string s; cin >> s; cin >> q; while(q--) { cout << s << "\n"; } return 0; } ``` ::: ## pC Last Christmas **Prepared by Colten** 這題我們可以一邊輸入一邊紀錄目前的最大值,當發現新輸入的數字比紀錄的最大值大時,則更新最大值。 :::spoiler 參考解答 (C++) ```cpp= #include <bits/stdc++.h> #define int long long using namespace std; signed main(void) { ios_base::sync_with_stdio(false); cin.tie(0); int n; cin >> n; int mx = -1e9; while(n--) { int input; cin >> input; mx = max(mx,input); } cout << mx << "\n"; return 0; } ``` ::: ## pD 公園調查 **Prepared by Colten** 這題主要會給一個區間 $h_1,h_2$,會在第 $h_1$ 的時間進入公園,第 $h_2$ 的時間離開公園。 那麼我們可以用兩個陣列分別紀錄在第 $i$ 時間進入的人數,以及離開的人數。 並用兩個變數 $now,ans$,分別記錄第 $i$ 小時的人數,以及更新人數最大值。 **那麼在第 $i$ 小時的人數為 $now + enter[i] - leave[i]$** :::spoiler 參考解答 (C++) ```cpp= #include <bits/stdc++.h> #define int long long using namespace std; int enter[10005],leave[10005]; signed main(void) { ios_base::sync_with_stdio(false); cin.tie(0); int q; int n; cin >> n; for(int i=0;i<n;i++) { int h1,h2; cin >> h1 >> h2; enter[h1]++; leave[h2]++; } int now = 0,ans = 0; for(int i=0;i<=10000;i++) { now = now + enter[i] - leave[i]; ans = max(ans,now); } cout << ans << "\n"; return 0; } ``` ::: ## pE 位數刪除 **Prepared by Colten** 這題其實我們可以從子任務來獲取一些提示。 既然這題沒有限制操作的次數,那麼我們可以知道,只要這兩個數字的所有位數之中,只要有其中一個位數的數字兩邊數字中都有出現,那麼答案必為 $Yes$。 :::spoiler 參考解答 (C++) ```cpp= #include <bits/stdc++.h> #define int long long using namespace std; signed main(void) { ios_base::sync_with_stdio(false); cin.tie(0); string a,b; cin >> a >> b; bool check = false; for(int i=0;i<a.size();i++) { for(int k=0;k<b.size();k++) { if( a[i] == b[k] ) { check = true; break; } } if( check == true ) break; } if( check == true ) { cout << "Yes\n"; } else { cout << "No\n"; } return 0; } ``` ::: ## pF Presentation Error **Prepared by Colten** 這題其實本來是 1 月實體賽要用的題目,但放上 CMS 出了點問題,於是就拿掉了。 - 輸出格式錯誤的狀況,我們可以知道,只要我們將兩個字串所有的空白字元都忽略掉,組合出兩個新的字串,假如新組合的字串兩兩相同但是不忽略空白字元的字串兩兩不相同,那麼這個狀況則是 Presentation Error 的情況。 - 那麼另一個狀況為,兩個字串組合後兩兩不相同,且不忽略空白字元的字串也兩兩不相同,那麼這麼狀況極為 Wrong Answer。 - 假設一開始的字串即兩兩相等,那麼這個狀況則為 Accepted。 ## pG 鬼滅之刀無限湯瑪士 **Prepared by Troy (大灣高中首次做事XD)** 這題我們觀察發現,當這個數列被操作 $n$ 次時,那麼這個數列又會變回跟原本一樣的數列。 我們可以發現,當 $a[i-1] > a[i]$ 這個情況出現 $2$ 次以上,那麼這個數列不可能操作成非嚴格遞增的數列。 **有個部分要注意,當假設上面這個情況出現過剛好 $1$ 次,那麼要順便檢查 $a[0] < a[n-1]$ 這個情況,假如成立,那麼這組數列也無法藉由操作變成非嚴格遞增的數列。** 像是這組測資就是上面第二個所說的情況 ``` 1 4 1 2 1 2 ``` **(假如序列的所有數字都一樣,那麼以上兩種情況都不會出現)** :::spoiler 參考解答 (C++) ```cpp= #include <bits/stdc++.h> #define int long long using namespace std; signed main(void) { ios_base::sync_with_stdio(false); cin.tie(0); int q; cin >> q; while(q--) { int n; cin >> n; vector <int> a(n); int check = 0,index = 0,mn = 3e9; for(int i=0;i<n;i++) { cin >> a[i]; if( i != 0 ) { if( a[i] < a[i-1] ) { check++; } } if( check != 0 && a[i] < mn ) { index = i; mn = a[i]; } } if( check != 0 && a[0] < a[n-1] ) { check++; } if( check >= 2 ) { cout << "No Nut\n"; } else { cout << "Oh Yes " << index << "\n"; } } return 0; } ``` ::: ## pH 名次數列 **Prepared by Colten** 這題其實是純離散化實作,不太了解離散化是什麼的人可以去網路上找一下 >< 離散化的實作有數種方式,二分搜或 set 搭配 map 都是常見的。 我們這邊提供的做法是 set + map 的作法。 我們先將元素都加入 set 裡面,再把 set 裡面的元素拿出 **(set 裡的元素預設依序由小到大)**,並多利用一個變數 $rk$ 紀錄名次,並把 $mp[拿出的元素]$ $=$ $rk$。 接著將依序輸出 $mp[a[i]]$ 就是 $a[i]$ 轉換為名次的結果。 :::spoiler 參考解答 (C++) ```cpp= #include <bits/stdc++.h> #define int long long using namespace std; int a[100005]; signed main(void) { ios_base::sync_with_stdio(false); cin.tie(0); int q; cin >> q; while(q--) { memset(a,0,sizeof a); int n; cin >> n; set <int> s; map <int,int> mp; for(int i=0;i<n;i++) { cin >> a[i]; s.insert(a[i]); } int rk = 1; for( auto i : s ) { mp[i] = rk; rk++; } for(int i=0;i<n;i++) { cout << mp[a[i]]; if( i != n - 1 ) cout << " "; } cout << "\n"; } return 0; } ``` ::: ## pI 隊友的選擇 **Prepared by Colten** 我們可以將這題分成三個部分來討論。 我們定義 $dp[i][k]$ 為,在第 $i$ 直行時,選擇第 $k$ 排的人時,能達到的最大值。 **如果這次要選擇第 $k$ 排的人,那麼我們上次的選擇就不能是 $k$** - 當 $k = 1$ 時,$dp[i][1] = max(dp[i-1][2],dp[i-1][3]) + a[i][1]$ - 當 $k = 2$ 時,$dp[i][2] = max(dp[i-1][1],dp[i-1][3]) + a[i][2]$ - 當 $k = 3$ 時,$dp[i][3] = max(dp[i-1][1],dp[i-1][2]) + a[i][3]$ :::spoiler 參考解答 (C++) ```cpp= #include <bits/stdc++.h> #define int long long using namespace std; int dp[100005][4],a[100005][4]; signed main(void) { ios_base::sync_with_stdio(false); cin.tie(0); int n; cin >> n; for(int i=1;i<=3;i++) { for(int k=1;k<=n;k++) { cin >> a[k][i]; } } dp[1][1] = a[1][1]; dp[1][2] = a[1][2]; dp[1][3] = a[1][3]; for(int i=2;i<=n;i++) { dp[i][1] = max(dp[i-1][2],dp[i-1][3]) + a[i][1]; dp[i][2] = max(dp[i-1][1],dp[i-1][3]) + a[i][2]; dp[i][3] = max(dp[i-1][1],dp[i-1][2]) + a[i][3]; } cout << max({dp[n][1],dp[n][2],dp[n][3]}) << "\n"; return 0; } ``` :::