# APCS 20240616 題解
## 第一題:特技表演(Accepted) [(題目敘述)](https://zerojudge.tw/ShowProblem?problemid=o076)
* 考點:迴圈、陣列、判斷
* 用for迴圈直接遍歷找到最長遞減(不變)的值
:::spoiler Example
```cpp=
#include <bits/stdc++.h>
using namespace std;
// 第一題程式碼 by 小律
int main() {
int n, arr[100005], cnt = 1, Max = 1;
cin >> n;
for(int i=0; i<n; i++) cin >> arr[i];
for(int i=1; i<n; i++){
if(arr[i] <= arr[i-1]){
cnt++;
Max = max(Max, cnt);
}
else cnt = 1;
}
cout << Max;
}
```
:::
## 第二題:電子畫布(Accepted) [(題目敘述)](https://zerojudge.tw/ShowProblem?problemid=o077)
* 考點:二維陣列
* 找到開始的地方為中心,從左上角 {${y-t, x-t}$} 的地方開始遍歷邊長為$$t*2-1$ 的正方形,在判斷是否為曼哈頓距離即可
:::spoiler Example
```cpp=
#include <bits/stdc++.h>
using namespace std;
// 第二題程式碼 by 小律
int main() {
int n, m, k, x, y, t, d, arr[105][105];
cin >> n >> m >> k;
memset(arr, 0, sizeof(arr));
while(k--){
cin >> x >> y >> t >> d;
int sy = y-t, sx = x-t;
for(int i=0; i<t*2+1; i++){
for(int j=0; j<t*2+1; j++){
if(sy+j >= 0 && sy+j < m && sx+i >= 0 && sx+i < n){
if(abs(sy+j - y) + abs(sx+i - x) <= t) arr[sx+i][sy+j] += d;
}
}
}
}
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
cout << arr[i][j] << ' ';
}
cout << '\n';
}
}
```
:::
## 第三題:缺字問題(Accepted) [(題目敘述)](https://zerojudge.tw/ShowProblem?problemid=o078)
* 考點:位元運算、DFS枚舉、二分搜
* 將子序列 $s$ 以sliding window 找到所有可能並且依字典序排序
* 接著用DFS枚舉 $C_k^L$ 種可能
* 最後用二分搜找字典序排序第一個的字串
:::spoiler Example
```cpp=
#include <bits/stdc++.h>
using namespace std;
// 第三題程式碼 by 小律
string alp, s, save, run;
vector <string> v;
int l, alp_S;
bool check = false;
void dfs(int now){
if(check) return;
if(now == l){
auto it = lower_bound(v.begin(), v.end(), run);
if(*it != run){
cout << run << '\n';
check = true;
}
return;
}
for(int i=0; i<alp_S; i++){
run[now] = alp[i];
dfs(now+1);
}
}
int main() {
cin >> alp >> l >> s;
alp_S = alp.size();
sort(alp.begin(), alp.end());
for(int i=0; i<l; i++) save += s[i];
v.push_back(save);
for(int i=l; i<s.size(); i++){
save.erase(0,1);
save += s[i];
v.push_back(save);
}
sort(v.begin(), v.end());
for(int i=0; i<l; i++) run += alp[0];
dfs(0);
}
```
:::
## 第四題:最佳選擇(Accepted) [(題目敘述)](https://zerojudge.tw/ShowProblem?problemid=o079)
* 考點:前後綴和、二分搜
* 先後綴和並且依據奇偶的差分類
* 再做前綴合搭配二分搜找到答案
* 要注意 $K$ 可能大於數列總和
* 要注意左右不一定都要拿(可以只拿左或只拿右)
:::spoiler Example
```cpp=
#include <bits/stdc++.h>
using namespace std;
// 第四題程式碼 by 小律
vector <int> odd[300005], even[300005];
int n, k, arr[300005] = {0}, tot = 0;
int main() {
cin >> n >> k;
for(int i=1; i<=n; i++){
cin >> arr[i];
arr[i] *= -1;
tot += arr[i];
}
// 解決k可能大於全部數字總和的問題
k = max(-k, tot);
int o = 0, e = 0, ans = 0, Min = 0;
// 先後綴和依據機奇偶數分類
for(int i=n; i>0; i--){
ans += arr[i];
if(arr[i] % 2) o++;
else e++;
if(e >= o) even[e-o].push_back(ans);
if(o >= e) odd[o-e].push_back(ans);
}
o = 0, e = 0, ans = 0;
// 再前綴和+二分搜找到要的答案
for(int i=0; i<=n; i++){
ans += arr[i];
if(arr[i] % 2) o++;
else if(arr[i] % 2 == 0 && arr[i]) e++;
if(o == e){
if(k <= ans) Min = min(Min, ans);
}
int save = e - o, div = k - ans;
if(e >= o){
auto it = lower_bound(odd[save].rbegin(), odd[save].rend(), div);
if(it != odd[save].rend()) Min = min(Min, *it+ans);
}
else if(o >= e){
save *= -1;
auto it = lower_bound(even[save].rbegin(), even[save].rend(), div);
if(it != even[save].rend()) Min = min(Min, *it+ans);
}
}
cout << -Min << '\n';
}
```
:::