# SCIST S5 演算法推廣課程隨堂練習題解參考程式碼
> 撰寫者 [name=4Yu]
[toc]
# 上午 C++ 語法 講師:4Yu
## 1. [d483. hello, world](https://zerojudge.tw/ShowProblem?problemid=d483)
`C++ 基本架構` `輸出`
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
cout << "hello, world\n";
return 0;
}
```
## 2. [a001. 哈囉](https://zerojudge.tw/ShowProblem?problemid=a001)
`輸入輸出` `變數`
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s;
cin >> s;
cout << "hello, " << s << '\n';
return 0;
}
```
## 3. [a002. 簡易加法](https://zerojudge.tw/ShowProblem?problemid=a002)
`輸入輸出` `變數` `運算子`
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a, b;
cin >> a >> b;
cout << a + b << '\n';
return 0;
}
```
## 4. [d827. 買鉛筆](https://zerojudge.tw/ShowProblem?problemid=d827)
`輸入輸出` `變數` `運算子`
> 提示:
> ||一打 12 支||
>
> 總價 = ||幾打 * 一打價錢 + 剩下的 * 一支價錢||
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n; cin >> n;
cout << (n / 12 * 50) + (n % 12 * 5) << '\n';
return 0;
}
```
## 5. [d064. ㄑㄧˊ 數?](https://zerojudge.tw/ShowProblem?problemid=d064)
`if-else 條件判斷式`
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n; cin >> n;
if (n % 2 == 0) cout << "Even\n";
else cout << "Odd\n";
return 0;
}
```
進階解法:[三元運算](https://seansie0830.github.io/posts/cpp-3opeator/)
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n; cin >> n;
cout << (n % 2 ? "Odd" : "Even") << '\n';
return 0;
}
```
## 6. [d058. BASIC 的 SGN 函數](https://zerojudge.tw/ShowProblem?problemid=d058)
`多重條件判斷式`
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n; cin >> n;
if (n > 0) cout << 1 << '\n';
else if (n == 0) cout << 0 << '\n';
else cout << -1 << '\n';
return 0;
}
```
## 7. [d498. 我不說髒話](https://zerojudge.tw/ShowProblem?problemid=d498)
`迴圈`
- for 迴圈寫法
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n; cin >> n;
for (int i=0; i<n; i++)
{
cout << "I don't say swear words!\n";
}
}
```
- while 迴圈寫法
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n; cin >> n;
while (n--)
{
cout << "I don't say swear words!\n";
}
}
```
## 8. [a058. MOD3](https://zerojudge.tw/ShowProblem?problemid=a058)
`迴圈` `多重判斷式`
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n; cin >> n;
int a = 0, b = 0, c = 0, t;
while(n--)
{
cin >> t;
if (t % 3 == 0) a++;
else if (t % 3 == 1) b++;
else c++;
}
cout << a << ' ' << b << ' ' << c << '\n';
return 0;
}
```
- 補充做法:switch-case 多重選擇
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n; cin >> n;
int a = 0, b = 0, c = 0, t;
while(n--)
{
cin >> t;
switch(t % 3)
{
case 0:
a++;
break;
case 1:
b++;
break;
case 2:
c++;
break;
}
}
cout << a << ' ' << b << ' ' << c << '\n';
return 0;
}
```
## 9. [d046. 文文採西瓜](https://zerojudge.tw/ShowProblem?problemid=d046)
`迴圈` `判斷式` `陣列`
- 用 while 迴圈不用到陣列寫法
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n; cin >> n;
int w, ans = 0;
while (n--)
{
cin >> w;
if (w <= 10) ans++;
}
cout << ans << '\n';
return 0;
}
```
- 用 for 迴圈 + 陣列寫法
```cpp=
#include <bits/stdc++.h>
using namespace std;
int N = 105, w[N];
int main()
{
int n; cin >> n;
int ans = 0;
for(int i=0; i<n; i++) cin >> w[i];
for(int i=0; i<n; i++)
{
if (w <= 10) ans++;
}
cout << ans << '\n';
return 0;
}
```
## 10. [f345. 新手練習題—陣列](https://zerojudge.tw/ShowProblem?problemid=f345)
`迴圈` `陣列`
```cpp=
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+5; // 宣告一個常數 N 作為陣列要開的空間,題目說(N<=10^6),保險起見多加個 5
int P[N]; // 先開好陣列所需的空間為 1000005
int main()
{
int n; cin >> n;
for(int i=0; i<n; i++) cin >> P[i];
for(int i=n-1; i>=0; i--) cout << P[i] << ' '; // 反過來輸出,注意 index 範圍要寫對
return 0;
}
```
# 下午 基礎資料結構與演算法 講師:sakinu
## 1. [e339. 前綴和練習](https://zerojudge.tw/ShowProblem?problemid=e339)
`前綴和建置` `迴圈` `陣列`
> 注意數字範圍可能會產生溢位(Overflow),變數型別要開 long long
```cpp=
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
long long A[N], pre[N];
int main()
{
int n; cin >> n;
pre[0] = 0;
for(int i=0; i<n; i++)
{
cin >> A[i];
pre[i+1] = pre[i] + A[i];
}
for(int i=1; i<=n; i++)
{
cout << pre[i] << " ";
}
}
```
## 2. [a693. 吞食天地](https://zerojudge.tw/ShowProblem?problemid=a693)
`前綴和應用` `EOF 輸入` `複雜度分析`
$O(n)$ 建前綴和,$O(1)$ 查詢
```cpp=
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int A[N], pre[N];
int main()
{
int n,m;
while(cin >> n >> m)
{
for(int i=0; i<n; i++)
{
cin >> A[i];
pre[i+1] = pre[i] + A[i];
}
int l,r;
while(m--)
{
cin >> l >> r;
cout << pre[r] - pre[l-1] << "\n";
}
}
}
```
## 3. [a694. 吞食天地二](https://zerojudge.tw/ShowProblem?problemid=a694)
`二維前綴和` `巢狀迴圈` `二維陣列` `EOF 輸入` `排容原理`
```cpp=
#include <bits/stdc++.h>
using namespace std;
const int N = 505;
int tb[N][N], pre[N][N];
int main()
{
int n,m;
while(cin >> n >> m)
{
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
{
cin >> tb[i][j];
pre[i+1][j+1] = tb[i][j] + pre[i+1][j] + pre[i][j+1] - pre[i][j];
}
}
int x1,y1,x2,y2;
while(m--)
{
cin >> x1 >> y1 >> x2 >> y2;
cout << pre[x2][y2] - pre[x2][y1-1] - pre[x1-1][y2] + pre[x1-1][y1-1] << "\n";
}
}
}
```
或是可以直接加在原本陣列上,不用多開個 pre 浪費空間
```cpp=
#include <bits/stdc++.h>
using namespace std;
const int N = 505;
int A[N][N];
int main()
{
int n,m;
while(cin >> n >> m)
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
cin >> A[i][j];
A[i][j] += A[i-1][j] + A[i][j-1] - A[i-1][j-1];
}
}
int x1,y1,x2,y2;
while(m--)
{
cin >> x1 >> y1 >> x2 >> y2;
cout << A[x2][y2] - A[x2][y1-1] - A[x1-1][y2] + A[x1-1][y1-1] << "\n";
}
}
}
```
## 4. [e447. queue 練習](https://zerojudge.tw/ShowProblem?problemid=e447)
`STL 資料結構` `queue 佇列`
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,t,x; cin >> n;
queue<int> q;
while(n--)
{
cin >> t;
if(t == 1)
{
cin >> x;
q.emplace(x);
}
else if(t == 2)
{
if(q.empty()) cout << "-1\n";
else cout << q.front() << "\n";
}
else if(!q.empty()) q.pop();
}
}
```
## 5. [i213. stack 練習](https://zerojudge.tw/ShowProblem?problemid=i213)
`STL 資料結構` `stack 堆疊`
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,k,x; cin >> n;
stack<int> s;
while(n--)
{
cin >> k;
if(k == 1)
{
cin >> x;
s.push(x);
}
else if(k == 2)
{
if(s.empty()) cout << "-1\n";
else cout << s.top() << "\n";
}
else if(!s.empty()) s.pop();
}
}
```
## 6. [n369. 3. 免費仔](https://zerojudge.tw/ShowProblem?problemid=n369)
`STL 資料結構` `set 集合`
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n; cin >> n;
string a,b;
set<string> s;
while(n--)
{
cin >> a >> b;
if(s.count(a)) cout << b << " account has been used\n";
else
{
cout << "welcome, " << b << "\n";
s.insert(a);
}
}
}
```
## 7. [b130. NOIP2006 1.明明的随机数](https://zerojudge.tw/ShowProblem?problemid=b130)
`STL 資料結構` `set 集合` `Range-based for loop`
> 運用了 set 可以去除重複元素並排序的特性
> 最後用 `for(auto i : s)` 遍歷全部元素並輸出
>
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,t; cin >> n;
set<int> s;
while(n--)
{
cin >> t;
s.insert(t);
}
cout << s.size() << '\n';
for(auto i : s) cout << i << ' ';
}
```
## 8. [c547. Bert 爬樓梯](https://zerojudge.tw/ShowProblem?problemid=c547)
`DP 動態規劃`
定義 dp[i] = 走到第 i 階時的最大走法數
轉移式為 dp[i] = dp[i-1] + dp[i-2]
因為一次只能走 1 階或 2 階,所以第 i 階只能從第 i - 1 階和第 i - 2 階走過來
先推出每項的值,每當詢問時直接查詢就好
```cpp=
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9+7, N = 10005;
int dp[N];
int main()
{
dp[0] = dp[1] = 1;
for(int i=2; i<=N; i++)
{
dp[i] = (dp[i-1] + dp[i-2]) % MOD;
}
int n;
while(cin >> n)
{
cout << dp[n] << "\n";
}
}
```
## 9. [d133. 00357 - Let Me Count The Ways](https://zerojudge.tw/ShowProblem?problemid=d133)
`DP 動態規劃`
定義 dp[i] = 用硬幣組合出 i 元的最大方法數
跟上一題差不多,只不過種類更多了,從 2 種(走 1 步或走 2 步)變成 5 種(5 種不同的幣值),所以我們再套一層迴圈去累計每種的方法數
```cpp=
#include <bits/stdc++.h>
using namespace std;
const int N = 30005, coins[5] = {1,5,10,25,50};
long long dp[N];
int main()
{
dp[0] = 1;
for(int i=0; i<5; i++)
{
for(int j=coins[i]; j<=N; j++)
{
dp[j] += dp[j - coins[i]];
}
}
int n;
while(cin >> n)
{
if(dp[n] == 1) cout << "There is only 1 way";
else cout << "There are " << dp[n] << " ways";
cout << " to produce " << n << " cents change.\n";
}
}
```
## 10. [d105. NOIP 2008 3.传球游戏](https://zerojudge.tw/ShowProblem?problemid=d105)
`DP 動態規劃`
定義 dp[i][j] = 經過 j 次傳球後回到 i 手上的路徑數
將 dp[0][0] 初始化為 1,因為經過 0 次傳球後回到 0 手上的路徑數只有一個
將 dp[0][1 ~ n-1] 初始化為 0,因為不可能經過 0 次傳球後回到 1 ~ n-1 手上
每次只能往左邊或右邊傳球,所以轉移式為 `dp[i][j] = dp[i-1][(j+1)%n] + dp[i-1][(j-1+n)%n];` 要 % n 讓它可以循環
我們要求經過 m 次傳球回到 0 手上的路徑數,取 dp[m][0] 即為答案
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n, m; cin >> n >> m;
int dp[31][31] = {0};
dp[0][0] = 1;
for(int j=1; j<n; j++) dp[0][j] = 0;
for(int i=1; i<=m; i++)
{
for(int j=0; j<n; j++)
{
dp[i][j] = dp[i-1][(j+1)%n] + dp[i-1][(j-1+n)%n];
}
}
cout << dp[m][0] << "\n";
}
```
## 11. [b304. 00673 - Parentheses Balance](https://zerojudge.tw/ShowProblem?problemid=b304)
`stack 進階應用` `括號匹配問題` `getline 輸入`
可以使用 stack 實作括號匹配問題,想法是維持 stack 內都只放入左括號,遇到右括號時,若與 stack 最上方的左括號匹配就 pop,否則就不是一個正確的運算式,例如:`[)` 無法匹配就不可能正確了。因為每對括號若匹配就會被 pop 掉,所以直到最後若 stack 為空,就是一個正確的運算式。
```cpp=
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n; cin >> n;
string s; getline(cin,s);
while(n--)
{
stack<char> sk;
getline(cin,s);
if(s == " ")
{
cout << "Yes\n";
continue;
}
bool ans = true;
for(int i=0; i<s.size(); i++)
{
if(s[i] == '(' || s[i] == '[' || sk.empty()) sk.push(s[i]);
else if(!sk.empty())
{
if((sk.top() == '(' && s[i] == ')') || (sk.top() == '[' && s[i] == ']')) sk.pop();
else { ans = false; break; }
}
}
if(ans && sk.empty()) cout << "Yes\n";
else cout << "No\n";
}
}
```
注意這題有空白行,所以要用 getline 輸入,雖然推廣課程沒教到,不過培訓課程會教,所以快報名吧!
# https://forms.gle/3dSRs2JsfqsDgnWx8