南大附中資訊研究社 NFIRC 1st

第 3 次社課講義

2023/11/08
主講:YuDong


😨今日流程

  1. YuDong 教分隔視窗
    請大家先開好上課要用到的東西
  2. ShiYu 點名 宣布幹部名單
  3. YuDong 講課前注意事項
  4. ShiYu 複習上次社課內容
  5. YuDong 主講這次社課新進度
  6. 繳社費 領社服 領飲料

😡課前準備

  • 先登入 Google 然後開好 Discord
  • 使用分隔視窗看: meet 直播畫面 + 社課講義 + Replit + Zero Judge 題單
  • 點名 請上次有繳社費的人來前面補簽收據
  • 宣布第一屆正式幹部名單

正式現任幹部名單

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →


Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

https://docs.google.com/spreadsheets/d/1_CVuBW38GNuu_-hs7-Q_ZMQHQrnDq1mKs08dqumvVzA/edit?usp=sharing


實習幹部名單

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →


💀課前注意事項

講義內所寫的程式碼都是用來舉例說明用
如果你是要解題目,請不要直接複製程式碼送出答案。
因為你只會吃到一堆 WA
然後沒有學到任何東西😭


💀課前注意事項

今天這堂可能對初學者來說有點難度
可能沒辦法當下在課堂吸收
但沒有關係,大家都有這份講義、有題單、有題解
也有開放給大家問問題的 Discord 社群

  • 回家的練習才是進步的關鍵
    課堂帶到的練習 + 回家的練習
    才能讓你自己有更顯眼的進步、理解更廣

💀課前注意事項

不會的地方、不懂的觀念
一定要發問
資研社可以讓你問到懂
如果某個人的說法你聽不太懂
也可以再問問其他人
多聽取不同的想法
也是進步的方式之一


本次社課 Slido 匿名提問

QR Code for NFIRC 第 3 次社課.png
https://app.sli.do/event/qmsxe97ZUwPmwQhgJu6K1i


複習第二次社課

  • 基本架構
  • 輸入輸出與變數使用
  • 四則運算
  • 程式規範與除錯
  • 延伸知識

基本架構

image.png


輸出

image.png

執行結果

image.png


變數宣告

image.png

  • 第 1 行中
    • 型別:整數 int ( integer 的縮寫)
    • 名稱:age
    • 值:未定義
  • 第 2 行中
    • 型別:字串 string
    • 名稱:name
    • 值:未定義

輸入

image.png


結合

image.png


執行結果

image.png


如何除錯 ? 常見錯誤

  • 忘記加分號 ;
  • 字拼錯
  • 忘記宣告變數就使用
  • cin >> cout << 串接方向記相反
  • 括號用錯或沒加或加錯地方
  • 全形半形沒切換

詳細除錯方法請至第二次社課講義的這頁


養成良好的程式撰寫習慣

程式沒寫錯 但沒縮排沒空格閱讀起來較困難

⚠️

image.png


適時的空格與縮排有助於閱讀與除錯

image.png


四則運算

image.png

image.png


整數除法

image.png


捨棄小數點

image.png

這節課會教如何保留小數點


% 求餘數

image.png

image.png


賦值運算

image.png

遞增遞減運算

image.png


四則運算的詳細內容

第二次社課講義詳細介紹四則運算


延伸知識

請至第二次社課講義


目錄

  • 變數

    • 基本變數型態 (Variable Type)
    • 全域(Global) & 區域(Local) 變數
    • 布林值 bool
  • 條件判斷式

    • 比較運算子
    • 邏輯運算子
  • 延伸知識


變數 Variables

在上一次社課中,我們簡單介紹了變數的基礎
以及介紹兩個變數型別:Integer (整數) 和 String (字串)
而現在我們要來介紹更多變數的型別!


認識新型別!

除了 int 與 string 以外,還有一些型別是我們常常用到的
這邊用一個表格整理給大家看

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

名稱 寫法 備註
整數 int 範圍 \(-2^{31}\) ~ \(2^{31}-1\)
大一點的整數 long long 範圍 \(-2^{63} \sim 2^{63} - 1\)
浮點數 double 儲存非整數的時候使用
字元 char 以 ' 包住字元
字串 string 以 " 包住字串
布林值 bool 僅有兩個值:true / false

變數大集合

image.png


保留小數點的除法

  • 強制轉型
    寫法是括號內包住要轉變的型別

image.png

括號內為我們要將其轉變的型別
double 就是浮點數(小數點)的意思
通常是取到小數點後第五位
這題輸出是 1.75


全域變數&區域變數

APCS 常考觀念

image.png

問:會輸出什麼?

答:10


解析原理

image.png

藍色 的區域是全域變數影響的範圍
綠色 的區域是區域變數影響的範圍
而在 main 函式當中,會先存取該函式內的變數的值。


讓我們研究新變數型別:Bool 布林值


image.png

他不是哥布林

在我們要表達一個條件、情況的真假時,就會用到布林值
等等要教的 條件判斷式 亦是如此


布林值簡介

一般來說,會用在我們要確認某個性質是否成立的時候
例如:檢查熱水器有沒有關
就只會有兩種情況:有關沒關

而布林值的值剛好只有兩種:true 真/false

布林值的重要性質:

  • true == 1
  • false == 0

來看一下宣告的布林值會怎麼用吧

image.png

輸出:
image.png


布林值宣告

宣告一個布林變數來儲存布林值。

  • bool 變數名稱 = <true/false>

image.png


用在條件判斷式?

if (1 < 2) { cout << "Yes, this is real."; }

這段程式碼是一個簡單的條件判斷式
1 < 2 這邊這個判斷結果是 【真】
在這裡,判斷結果的布林值就是: true


條件判斷式

既然我們學會了 int 和 string 變數 的運用
剛剛也有複習ㄌ
那麼如果我們需要讓程式在某些情況下
執行我們要所要的結果
就會需要進行 判斷

而今天要介紹的 條件判斷式 就是用來幫助流程判斷


在開始之前

先來認識一下 基礎運算子邏輯運算子吧!
在【條件判斷式】中
這些運算子是相當重要的
要判斷,就要先有比較。
要比較,就要先有邏輯。


比較運算子

定義 運算子 解釋
相等 == a 與 b 相等 50 == 50
不相等 != a != b 就像 50 != 100
大於 > a > b 就像 100 > 50
小於 < a < b 就像 50 < 100
大於等於 >= a >= b 就像 100 >= 50
小於等於 <= a <= b 就像 50 >= 100

要注意的是: 等於是 == 而不是 =

在程式語言中, = 是用於賦值給變數的
== 才是「判斷是否相等」的意思


邏輯運算子

或(OR): || 
且(AND): && 
相反(NOT): !

SA 講義有超級詳細的介紹
各位可以先記錄下來,或者等等回來翻閱這裡
下面來介紹一下 邏輯優先度


運算優先度

  • 括號內的先,之後再依序由左至右。

課外文章:運算子的優先權
接下來,要開始正式進入到 【條件判斷式】


條件判斷式:if

顧名思義,就是【如果】

舉例:

  • 如果 期末成績 \(a\) \(<\) \(40\) 那麼 你被死當 哈哈


if 的語法細節

#include <bits/stdc++.h> using namespace std; int main() { int a,b; cin >> a >> b; if(a > b) { cout << a << "is bigger than " << b << "\n"; } return 0; }
  • 可以單獨存在、可以寫很多層
  • 條件由小括弧包住 → \(a > b\)
  • 滿足條件後要做的事情由大括號包住 → 第 \(9\)
  • 若滿足條件後要做的事情只有一個指令,可不包大括號

簡化寫法:不包大括號

#include <bits/stdc++.h> using namespace std; int main() { int a,b; cin >> a >> b; if(a > b) cout << a << "is bigger than" << b << "\n"; return 0; }
  • 若滿足條件後要做的事情只有一個指令,可不包大括號

使用剛剛的例子

如果 期末成績 \(a\) \(<\) \(40\) 那麼 你要去重補修

#include <bits/stdc++.h> using namespace std; int main() { int a = 39; // 這是你的期末分數 if (a < 40) { // 如果 期末成績 a < 40 那麼 就要去重補修了。 cout << "You must retake the course. HAHA"; } return 0; }

執行結果

You must retake the course. HAHA

那如果有第二個條件呢?

例子:
如果 期末成績 \(a < 40\) 哈哈重修
否則 \(a >= 60\) 代表通過

可以看到 有兩種條件
那麼我們該怎麼去做判斷呢?


這時候就要來介紹 else 了

else 也就是【否則

#include <bits/stdc++.h> using namespace std; int main() { int a,b; cin >> a >> b; if(a > b) { cout << a << "is bigger than" << b << "\n"; } else { cout << a << "is smaller than" << b << "\n"; } return 0; }
  • 無法單獨存在,前面一定要有一個 if
  • 同 if,不符合第一個條件要做的事情包在大括號裡面
  • 若不符合條件後要做的事情只有一個指令
    也可不包大括號

舉個例子:
如果 期末成績 \(a < 40\) 重修
否則 \(a >= 60\) 通過 來看

期末成績 \(a < 40\)第一個條件
\(a >= 60\) 則是剩下的條件

如果所有的 if 都不成立,那麼 else 的部份將被執行。

我們來看看 else 怎麼實作的吧


else 實作示範

#include <bits/stdc++.h> using namespace std; int main() { int a = 39; // 這是你的期末分數 重修的那種。 if (a >= 60) { // 如果 期末成績 a >= 60 那麼你通過了。 cout << "You passed."; } else { // 期末成績 a 沒有 >= 60 那麼你要重修了 哈哈。 cout << "You must retake the course. HAHAHAHAHA."; } return 0; }

而在上面的程式碼中 ,我們的分數為 \(39\)
明顯 \(a\)\(< 40\)
else 則是處理了 \(a >= 60\) 以外的情況
這意味著,我們終究逃不過重修的命運 x)


等等 那第三種情況怎麼辦?

很多情況是沒有辦法直接二分法解決的
這時候,就要用到我們的 else if
用法與 else 大致相同

舉個例子吧:

如果 期末成績 \(a >= 60\) 表示通過
\(40 <= a\)\(a < 60\) 則是補考人
否則 \(a < 40\) 重修


else if 實作範例

如果 期末成績 \(a >= 60\) 通過
\(40 <= a\)\(a < 60\) 是補考人
而當 \(a < 40\) 重修

#include <bits/stdc++.h> using namespace std; int main() { int a = 53; // 這是你的期末分數 if (a >= 60) { // 如果 期末成績 a >= 60 那麼你通過了。 cout << "You passed."; } else if (a >= 40) { // 期末成績 40 <= a < 60 的情況 cout << "You must attend the make-up exam. RIP."; } else { // 期末成績 a 沒有 > 40 那麼你要重修了 哈哈。 cout << "You must retake the course. HAHAHAHAHA."; } return 0; }

有辦法同時判斷多個條件嗎

舉例:
期末成績 \(a > 75\)\(a <= 100\) 是 電神
輸出 Orz

這種情況 該怎麼寫呢?


第一種作法

#include <bits/stdc++.h> using namespace std; int main() { int a = 88; // 這是期末分數 八成是別人的 x) if (a > 75) { //如果 a > 75 if (a <= 100) { //如果 a <= 100 cout << "Orz"; } } return 0; }

這樣寫是正確的
但是 能不能再簡化一點呢?
太多的 if 包在一起
會影響日後 debug 的難度與可讀性。


還記得我們剛剛提到的

邏輯運算子

或(OR): || 
且(AND): && 
相反(NOT): !

幫各位搬運過來了


第二種作法:邏輯運算子

還記得我們剛剛提到的 邏輯運算子

忘記的可以回去複習一下

利用邏輯運算子,可以讓程式碼更簡潔、好讀、易於維護

#include <bits/stdc++.h> using namespace std; int main() { int a = 88; // 這是期末分數 八成是別人的 x) if (a > 75 && a <= 100) { //如果 a > 75 而且 a <= 100 cout << "Orz"; } return 0; }

這樣 我們就不需要再包一個 if 在第一個 if 裡面了


Practice Time

先來複習一下怎麼寫題目 xD


怎麼寫題目?

  1. ZeroJudge 之後,先登入

image.png


  1. 點擊自己的帳號,按下【南大附中】的課程

image.png


  1. 選擇你要練習的課次、題目
    image.png

  1. 按下 參加隨堂練習 即可練習題目
    image.png

Practice Time

如果遇到問題,歡迎舉手發問

也可以在 slido 上面發問!
哪邊聽不懂的也可以再重講一次歐
助教們都會去幫忙喔

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →


Practice Time

必做題:
ZJ d064 -ㄑㄧˊ 數?
ZJ d058 - BASIC 的 SGN 函數


計時器


練習題

ZJ d068 - 該減肥了!
ZJ a003 兩光法師占卜術
ZJ d073 - 分組報告
ZJ d050 妳那裡現在幾點了?
ZJ d060 - 還要等多久啊?
ZJ d066 - 上學去吧!
ZJ d460 - 山六九之旅
ZJ b877 - 我是電視迷


挑戰題:

(等完成上面的題目再挑戰看看!)

ZJ d067
挑戰題詳細解析

TOJ 額外練習題

  • 想自己練習的記得要註冊(點右上角的Reg)
    雖然不會算進社團積分
    但可以幫你對於這個語法更穩固
    有想要額外練習、期末賽開秀、或考 APCS 的人
    都建議可以做做看,一樣會給題解

TOJ529
TOJ531


必做題解析


ZJ d064 - ㄑㄧˊ 數?

題目整體的意思就是:判斷 \(n\) 是不是奇數
如果是奇數輸出 Odd,否則輸出 Even


AC Code

  • 我們可以用剛剛學到的 if else 條件判斷式去寫
    並且利用 \(\%\),取餘數就可以知道是否為偶數了
#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; }

ZJ d051 - BASIC 的 SGN 函數

題目把它描述的看起來很難

破題關鍵:

  • 如果 \(n > 0\) 輸出 \(1\)
  • 否則 如果 \(n = 0\) 輸出 \(0\)
  • 否則 請輸出 \(-1\)

AC Code

  • 一樣,我們利用 if else 條件判斷式去進行判斷
    依照每一個條件,去輸出對應的答案
#include <bits/stdc++.h> using namespace std; int main() { int n; cin >> n; if(n > 0) cout << 1 << "\n"; //如果 n > 0 else if(n == 0) cout << 0 << "\n"; //如果 n = 0 else cout << -1 << "\n"; //如果 n < 0 return 0; }

延伸知識

  • int 的範圍 溢位 開 long long
  • 有號無號 signed & unsigned
  • INT_MIN, INT_MAX
  • min( ), max( )
  • 小數點後位數 setprecision( )
  • 浮點數的誤差
  • 三元運算
  • 多條件判斷式 switch
    • XBOX, PS4

int 的儲存範圍

剛剛提到,int 儲存的數字範圍是 \(-2^{31} \sim 2^{31}-1\)
精確來說是 \(-2147483648 \sim 2147483647\)
這串數字不必背起來 只需要知道大概是 \(2 \times 10^{10}\) 就好


溢位 overflow

若數字比能儲存的範圍還大 就會發生溢位
產生 非預期的結果

更多詳細知識可閱讀 變數上限與溢位 by SA


競程小技巧(毒瘤)

為了避免掉有些題目給的數字較大
使用 int 會有溢位問題,通常會用:
image.png


但要注意做了這件事之後
整份程式碼的 int 就都會是 long long 的狀態了
使用後要記得順便將 main 函式回傳的 int 改成 signed
image.png

除了競程用途以外,強烈建議不要使用於開發


unsigned & signed

無號整數有號整數

  • signed 的儲存範圍介於 \(-2147483648 \sim 2147483647\)
  • unsigned 的儲存範圍則是 \(0 \sim 4294967295\)
    (沒有負數且正數是 signed 的兩倍)

INT_MAX & INT_MIN

INT_MAX = 2147483647 INT_MIN = -2147483648
  • 這兩個通常用來做比大小的初始值給定

更多的巨集表達式在這篇文章
有興趣的可以看一下


min( ) & max( ) 函式

  • min( ):回傳最小值
  • max( ):回傳最大值

函式用法

  • min(a,b):對 \(a\ b\) 取最小值

  • max(a,b):對 \(a\ b\) 取最大值

  • 兩個函式都具有交換律
    所以可以這樣用:

image.png
延伸題:ZJ d065. 三人行必有我師


setprecision() 函式

  • 取到小數點後第 \(n\)
  • 通常會加 fixed 在前面
    確保固定小數位數

image.png

輸出結果

3.14159

延伸題:ZJ d051. 糟糕,我發燒了!

轉換公式:\((f-32) \times 5/9\)


浮點數的誤差

剛剛提到的 比較運算子 == 為相等之意
但是浮點數的比較因為誤差的關係
不能使用 == 進行比較
更多的資訊在這邊文章:浮點數的誤差
image.png


三元運算


一元、二元、三元的差別

定義:用到幾個東西
image.png


三元運算語法

  • 條件 ? 符合條件要做的事情 : 不符合條件要做的事情
#include <bits/stdc++.h> using namespace std; int main() { int age; cin >> age; cout << (age > 18 ? "is Adult" : "is a Kiddo") << "\n"; return 0; }

與 if 的比較

如果不用三元運算:

#include <iostream> using namespace std; int main() { int age; cin >> age; if(age > 18) { cout << "is Adult\n"; } else { cout << "is a Kiddo\n"; } return 0; }

程式碼又臭又長💀


用了三元運算後

#include <bits/stdc++.h> using namespace std; int main() { int age; cin >> age; cout << (age > 18 ? "is Adult" : "is a Kiddo") << "\n"; return 0; }

程式碼變得更簡潔了 讚啦


多條件判斷式 switch

image.png

對,就是這個 switch
今天來介紹一下 怎麼在馬力歐賽車裡面打網球
switch 語法


使用時機

在競程中比較常用到 if
switch 則相對少見
但以下幾個時機,是適合使用 switch 的

  1. 離散的情況
    值是有限的且不連續的;不存在無限多的情況
  2. 單個變數多個值
    對於一個變數有多種可能
    且這些值沒有過於複雜的關係 可以用 switch 簡化
  3. 簡單的多分支邏輯
    多種不同情況,但每次都只涉及單一個變數的比較
    或者是只做些微的改變
  4. 多個相等性比較

語法

switch (運算式或變數名稱) { case 符合數字或字元: 符合此 case 執行的東西; break; case 符合數字或字元: 符合此 case 執行的東西; break; default: 符合此 case 執行的東西; break; }

請記得在每個 case 中 break


switch 語法示範

給定一 \(N\),表示這次段考的分數(\(0 \le N \le 100\)
學校為了統計方便
會將分數統一都會除以 \(10\)
如果分數等於 \(9\)\(10\),其對應等第為 A
如果分數等於 \(8\),其對應等第為 B
如果分數等於 \(7\),其對應等第為 C
如果分數等於 \(6\),其對應等第為 D
其餘的情況,都等第都為 E


switch 語法示範

image.png


XBox & PS5

礙於時間因素,這邊給大家兩個連結


回饋表單

感謝各位認真參與第三次社課
一如既往,需要各位提供意見給我們
令我們知道各位在課程當中的想法

請到 Discord 社團公告填寫或用手機掃描以下 QR Code
qr.ioi.tw.png


繳社費 領社服 領飲料

Select a repo