# 競程班第二堂社課 :::spoiler 目錄: [TOC] ::: ## 開始之前 來稍微複習一下上一堂的內容 ### 程式架構: ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ //code return 0; } ``` --- ### 變數型態: ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ int a = 1234; string s1 = "qwerty", s2 = "This is a string."; char c = 'a'; float f = 1.234; bool b = true; //bool b = 1; return 0; } ``` --- ### 輸入輸出、四則運算: ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ int a,b; string s1,s2; cin>>a>>b>>s1>>s2; cout<<"a + b = "<<a+b<<endl; cout<<"s1 is "<<s1<<endl; cout<<"s2 is "<<s2<<endl; return 0; } ``` --- ### 條件式: ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ int n; cin>>n; if(n == 0){ cout<<"n is 0"<<endl; } else if(n == 1){ cout<<"n is 1"<<endl; } else if(n < 0){ cout<<"n is negative"<<endl; } else{ cout<<"n is very big"<<endl; } return 0; } ``` :::warning :warning: == 用於判斷 = 用於賦值 ::: --- ### 布林運算子: 計算布林值之間的關係,回傳布林值 **AND: && OR: || NOT: !** | AND | True | False | |----| ---- | ----- | | True | True | False | | False | False | False | | OR | True | False | |----| ---- | ----- | | True | True | True | | False | True | False | | NOT | True | False | |----| ---- | ----- | |----| False | True | ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ int a; cin>>a; if(a > 0 && !( a % 2 == 0)){ cout<<a<<" is a positive odd number"<<endl; } else{ cout<<a<<" is not a positive odd number"<<endl; } return 0; } ``` :::warning :warning: 多用括號 ::: --- ## IDE 整合開發環境 通常包含編輯器、除錯器、編譯器or直譯器。 ### [vscode](https://code.visualstudio.com/) ![](https://hackmd.io/_uploads/HkC9q2jep.png) 不含編譯器,安裝過程麻煩 ### [Code::Blocks](https://www.codeblocks.org/) ![](https://hackmd.io/_uploads/ryflihoep.png) APCS指定IDE ### [Dev-C++](https://www.bloodshed.net/) ![](https://hackmd.io/_uploads/SJbPh3ila.png) 介面簡潔、適合入門。但版本很舊,所以我都用[embarcadero dev-c++](https://www.embarcadero.com/free-tools/dev-cpp/free-download)(語言記得選英文) ![](https://hackmd.io/_uploads/S1_Lh2sxT.png) ## OJ online judge,線上解題系統 ### [Codeforces](https://codeforces.com/) 題目、比賽超多,打競程的通常用這個最多,不過很多怪題。 ### [CSES](https://cses.fi/problemset/list/) 只有300題,但都是很經典的題型,刷這個對APCS、TOI很有幫助。 ### [Atcoder](https://atcoder.jp/home) 日本網站,因此比賽時間比Codeforces舒服多了。 ### [ZeroJudge](https://zerojudge.tw/) 台灣網站,有APCS和很多比賽的考古題 ### [TCIRC](https://judge.tcirc.tw/) 一中電研的OJ,有AP325的習題。 ### [TIOJ](https://tioj.ck.tp.edu.tw/) 建中的,有IOICamp和NPSC的題目 ## 學習資源 [USACO Guide](https://usaco.guide/) 英文,各個難度都有,有很多參考code [AP325](https://drive.google.com/drive/folders/10hZCMHH0YgsfguVZCHU7EYiG8qJE5f-m) 中文,適合APCS 3級 ## 如何寫題目 以Codeforces為例。 在problemset裡面可以照難度或通過人數排序,假設你選了通過人數最多的[這一題](https://codeforces.com/problemset/problem/4/A) ![](https://hackmd.io/_uploads/ryvpf6sx6.png) 題目大意:給你一個正整數$w$,問它是否可以拆成兩個正偶數之和。 解法: $w$必須要是不為2的正偶數才會是`Yes`,否則都是`No`。 打開你的Dev-C++,打程式: ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ int w; cin>>w; if(w % 2 == 0 && w != 2){ cout<<"YES"<<endl; } else{ cout<<"NO"<<endl; } return 0; } ``` 存檔後(xxx.cpp)按下compile and run ![](https://hackmd.io/_uploads/HJ2dwTsla.png) 會出現一個exe檔,你可以在這裡測試範例測資,輸入8,按Enter,應該輸出YES ![](https://hackmd.io/_uploads/HyxG_6je6.png) 回到Codeforces,在右方找到這個。 ![](https://hackmd.io/_uploads/rypRdpsga.png) Luaguage選擇GNU C++20 11.2.0 (64bit,winlbs),檔案選擇剛剛的cpp檔(不是exe檔) submit後會到這個畫面 ![](https://hackmd.io/_uploads/SJd3K6oxa.png) 按 # 可以看到詳細資料 Verdict大致可能有以下結果(各OJ皆如此): * AC (Accept): 你通過了,你超電 * WA (Wrong Answer): 表示答案錯誤 * TLE (Time Limit Exceed): 表示執行超過時間限制 * MLE (Memory Limit Exceed): 表示程序執行超過記憶體限制 * OLE (Output Limit Exceed): 表示程序輸出檔超過限制 * RE (Runtime Error): 表示執行時錯誤,通常為記憶體配置錯誤 如:使用了超過陣列大小的位置 * CE (Compile Error): 表示編譯錯誤。 ## 迴圈 ### while 使用方式: while(繼續的條件){} 會重複大括號內的程式直到判斷式為`false`(0) --- ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ int a = 10; while(a > 0){ cout<<a<<' '; a -= 1; } return 0; } ``` 輸出: ![](https://hackmd.io/_uploads/SJK42J2e6.png) --- :::info 補充: ```cpp while(a > 0) ``` 也可以寫成 ```cpp while(a) ``` 因為當把一個`int`當作條件式時,$0$會視為`false`,而其他數字會被視為`true`。 因此,`while(1)`會是一個無限迴圈。 ::: --- :::info 補充: ```cpp= int n; while(cin>>n){ //code } ``` cin >> n是取得n之後,把n賦予給cin,如果能賦予,就會回傳true,則條件式成立,進入while迴圈 反之,如果輸入無效或EOF(End of File),n無法賦予給cin,則條件式不成立,跳脫迴圈 ::: --- ### for 使用方式: for(開始迴圈前做的事;繼續的條件;每跑一圈**後**會做的事){} ![](https://hackmd.io/_uploads/By4yoenla.png) --- ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ for(int i = 0; i <= 10; i++){ cout<<i<<' '; } return 0; } ``` 寫成while的話就是: ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ int i = 0; while(i <= 10){ cout<<i<<' '; i++; } return 0; } ``` 輸出: ![](https://hackmd.io/_uploads/HkM8oenea.png) --- ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ for(int i = 1; i < 1000; i *= 2){ cout<<i<<' '; } return 0; } ``` 輸出: ![](https://hackmd.io/_uploads/r1dpig3l6.png) --- ### 巢狀迴圈 就字面上的意思 ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ for(int i = 1; i <= 4; i++){ for(int j = 0; j < i; j++){ cout<<'*'; } cout<<endl; } return 0; } ``` 輸出: ![](https://hackmd.io/_uploads/rJDmAe2la.png) --- ### break 與 continue break: 跳脫迴圈 continue: 結束這一圈 --- ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ for(int i = 0; ; i++){ //for迴圈沒有條件式會視為無限迴圈 if(i > 10){ break; } cout<<i<<' '; } return 0; } ``` 輸出: ![](https://hackmd.io/_uploads/r1eYFfhe6.png) --- ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ for(int i = 0; i < 10; i++){ if(i % 2 == 0){ continue; } cout<<i<<' '; } return 0; } ``` 輸出: ![](https://hackmd.io/_uploads/BJuE5G2g6.png) --- ### 變數的有效範圍 對於在for迴圈內宣告的變數,只會在大括號範圍內有效。 ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ for(int i = 0; i < 10; i++){ //code } cout<<i; //<---這裡會報錯 } ``` ## 陣列 一串東西 宣告: ```cpp int a[3], b[4]={0,1,10000,-1}; string s[2]={"qwerty","123456"}; ``` 中括號內是大小 :::warning :warning: 索引值(index)從0開始,大小為3的陣列裡面分別是第0項、第1項、第2項。 ::: ### 存取 ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ int a[3]={100, 1, -10}; a[1] = 6; //{100,6,-10} a[0] += 99; //{199,6,-10} a[2] -= a[1]; //{199,6,-16} a[0] ++; //{200,6,-16} return 0; } ``` ### 遍歷陣列 --- ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ int a[4] = {-1, 2, 1000, 0}; for(int i = 0; i < 4; i++){ cout<<a[i]<<' '; } return 0; } ``` 輸出: ![](https://hackmd.io/_uploads/BJ9p2zne6.png) --- 題目要輸入一個陣列時,通常會先跟你說它的大小,像[這一題](https://cses.fi/problemset/task/1094): ![](https://hackmd.io/_uploads/rJANxmhxa.png) ![](https://hackmd.io/_uploads/HJWvx72ga.png) ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ int n; cin>>n; int a[n]; for(int i = 0; i < n; i++){ cin>>a[i]; } //code } ``` --- ### 二維陣列 即陣列的陣列,可以想成是一個表格。 宣告: ```cpp int a[2][3]={{1, 9, 10}, {4, 0, -6}}; bool b[100][3][4]; //三維陣列 ``` 基本上和一維一樣。 --- ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ int n, m; cin>>n>>m; int a[n][m]; for(int i = 0; i < n; i++){ for(int j = 0; j < m; j++){ cin >> a[i][j]; } } } ``` --- ## 常用函式 需`#include<algorithm>`,如果已經用了`#include<bits/stdc++.h>`就不用。 ```cpp= int a = 3, b = 4, c = 5; int mn = min({a, b, c}); int mx = max({a, b, c, -100000}); //如果只有兩項可以不用大括號,如 max(a,b) swap(a, b); //a 變為 4,b 變為 3 ``` ## 練習題 :::warning :warning: 如果運算過程會超過`int`範圍($-2^{31}$到$2^{31}-1$),請改用`long long` ::: [b016: 山谷的回聲](https://judge.tcirc.tw/ShowProblem?problemid=b016) :::spoiler AC code ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ int n; cin>>n; for(int i = 0; i < n; i++){ cout<<"Hello, World!"<<endl; } return 0; } ``` ::: \ [b021: 電電找因數](https://judge.tcirc.tw/ShowProblem?problemid=b021) :::spoiler AC code ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ int n; while(cin>>n){ for(int i = 1; i <= n;i++){ if(n % i == 0){ cout<<i<<" "; } } cout<<endl; } } ``` ::: \ [b026: 乖乖寫作業](https://judge.tcirc.tw/ShowProblem?problemid=b026) :::spoiler AC code ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ int n; cin>>n; long long a[n]; for(int i = 0; i < n; i++){ cin>>a[i]; } for(int i = n - 1; i >= 0; i--){ cout<<a[i]<<" "; } cout<<endl; return 0; } ``` ::: \ [b027: 找出學霸](https://judge.tcirc.tw/ShowProblem?problemid=b027) :::spoiler AC code ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ int n; while(cin>>n){ int mxpos, mxval = -1, mnpos, mnval = 101; for(int nowpos = 0; nowpos < n; nowpos++){ int nowval; cin>>nowval; if(nowval > mxval){ mxval = nowval; mxpos = nowpos; } if(nowval < mnval){ mnval = nowval; mnpos = nowpos; } } cout<<mxpos + 1<<' '<<mxval<<' '<<mnpos + 1<<' '<<mnval<<endl; } return 0; } ``` ::: \ [Weird Algorithm](https://cses.fi/problemset/task/1068) :::spoiler AC code ```cpp= #include<bits/stdc++.h> using namespace std; signed main(){ long long n; cin>>n; cout<<n<<" "; while(n != 1){ if(n % 2 == 1){ n = n * 3 + 1; cout<<n<<" "; } else{ n /= 2; cout<<n<<" "; } } return 0; } ``` ::: \ [Missing Number](https://cses.fi/problemset/task/1083) :::spoiler 提示: 可以用數學解 ::: :::spoiler AC code ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ long long n,sum; cin>>n; sum=n * (n + 1) / 2; for(int i = 0; i < n - 1; i++){ int a; cin>>a; sum-=a; } cout<<sum<<endl; ``` ::: \ [Increasing Array](https://cses.fi/problemset/task/1094) :::spoiler AC code: ```cpp= #include<bits/stdc++.h> using namespace std; int main(){ int n, pre, now; long long ans=0; cin>>n; cin>>pre; for(int i = 1; i < n; i++){ cin>>now; if(pre > now){ ans += pre - now; now = pre; } pre = now; } cout<<ans; return 0; } ``` :::