競賽程式介紹+演算法初探

9/21 複賽培訓[0]

327 王培軒

講師介紹

王培軒

  • 110北市賽二等獎、全國賽24名==
  • 327
  • 乏善可陳
  • 漠不關心資訊社事務

張庭瑋 aka ACOrz

  • 芒國手
  • CF: Alvingogo
  • 2022 TOI 1!
  • 110北市賽資訊一等獎、數學一等獎
  • 110全國賽資訊三等獎
  • TMO 3!
  • 超級強

校隊培訓會有強強的學長(?

Disclaimer

這份簡報大量參考去年(2021)的校內培訓簡報,

主要是加入了一些我覺得不錯的東西,然後更新了一下資訊

競賽程式簡介

我想當校隊!

可是,校隊要幹嘛啊?

普通型高級中等學校數理及資訊學科能力競賽

9/12 校內初賽

10/4 校內複賽

11/20 北市賽

12月 全國賽

25人進複賽

11人校隊

9人進全國賽

10人進選訓

資訊奧林匹亞

12月 全國賽

3月初 入營考

3月底 一階

4月 二階

10人進選訓

20人+保障名額

12人進二階

4名國手

7月 IOI

入營考只要APCS實作3以上或通過海選就能考

我好想比賽!

只有能競跟資奧嗎?

好玩的比賽們

成大賽 8月 團體賽,停辦好幾屆了,今年復活!
YTP 8月 團體賽,好吃、有錢拿,前十幾名可以做專題,
舉辦的公司(精誠)很有錢
HP codewar 11月 個人賽,這兩年線上賽很無聊(去年還撞全國賽),聽說實體有很多獎品可以拿,今年新增大專組
ISSC 團體賽,要去東海大學比,題目真的有點爛,
今年簡章不知為啥還沒出來
NPSC 12月 題目非常好,往年也是很多獎品,
但去年只有線上賽跟獎狀

酷酷的線上比賽

我以為寫程式只要會語法...

演算法是什麼?

演算法:解決問題的方法

問題:可以被客觀定義、描述的問題

方法:可以被客觀描述的流程與步驟。大部分演算法應該對同一種類的問題都適用。

 

例:給定\( a,b \),求\( gcd(a,b) \),其中\(1 \leq a,b \leq 10^9 \)

演算法應該要在題目滿足條件的情況下,輸出正確的答案。

而在競賽程式中

競賽程式與一般軟體工程師做的事情有些不同:

  • 問題、答案通常是以純文字輸入、輸出
  • 程式運行的時間必須滿足限制,如時間、記憶體使用量等
  • 由於競賽是限時的,因此通常不考慮寫個幾百行的程式,也不能使用一些擴充套件(但有些可以,之後會介紹)
  • 若一個比賽有即時回饋的話,你會將程式碼上傳到Judge,然後Judge會以不同的測資測試你的程式是否能得到正確答案

我想變強!

要怎麼做...

教學網站

課程

題目

演算法初探

複雜度分析

執行時間、空間消耗的估算

小問題

給你一個陣列\(a\),請問選兩個數字相減的最大值是多少?

哪個比較快?

int a[n];
int ans=-INF;
for(int i=0;i<n;i++){
    for(int j=i-1;j>=0;j--){
    	ans=max(ans,a[i]-a[j]);
    }
}
cout << ans << '\n';
int a[n];
int mx=-INF,mn=INF;
for(int i=0;i<n;i++){
    mx=max(mx,a[i]);
    mn=min(mn,a[i]);
}
cout << mx-mn << '\n';

運算次數

n=10 45次減法、45次取max 10次取min、10次取max
1000 499500/499500 1000/1000
1000000 5e11/5e11 1000000/1000000

無法接受

時間複雜度

左邊的程式有兩層迴圈,運算次數跟\(n^2\)成正比,右邊的程式則只有一層迴圈,運算次數跟\(n\)成正比。

我們就會說左邊的時間複雜度是\( \Omicron (n^2)\),右邊的是\( \Omicron (n)\)

複雜度

計算資源的消耗量(如時間、空間、計算次數)隨著問題規模增加,消耗量的增加方式

通常我們會用\( \Omicron (f(n))\)來表示,例如:\( \Omicron (n) \)、\( \Omicron (n^2) \)、\( \Omicron ( \log n) \)

(\( \Omicron \)為第15個希臘字母Omicron,只是大家都打\(O\))

可以簡單理解為只留最高次方的那項、並省略常數

建議大家不必細究嚴謹定義,等上大學在學><

時間複雜度與執行時間

n的大小(大概)

\(10\)

\(20\)

\(100 \sim 500\)

\(1000 \sim 5000\)

\(10000 \sim 10^5\)

\(10^5 \sim 10^6\)

\(10^6 \sim 10^7\)

\( \geq 10^9\)

對應的複雜度

\( \Omicron (n!) \)

\( \Omicron (2^n), \Omicron (n \times 2^n) \)

\( \Omicron (n^3) ,\Omicron (n^3 \log n) \)

\( \Omicron (n^2), \Omicron (n^2 \log n) \)

\( \Omicron (n \sqrt{n}) \)

\( \Omicron (n \log n) \)

\( \Omicron (n) \)

\( \Omicron ( \log n) \)

電腦每秒能夠運行大約\( 3 \times 10^8 \)個運算

北市賽Judge大概每秒\( 10^{10} \)

(參考用,實際上位元運算、加減比乘除、取模快很多)

 

空間複雜度

通常空間限制會是64MB~256MB不等。

每個int是4bytes,所以大概可以存\(10^7 \sim 10^8 \)個int

因此多半時候只要時間跑得完,空間就夠用

如果使用vector更是如此

因此我們只需在意時間複雜度

但真的只要數迴圈幾層就可以了嗎?

練習

	int n;
cin >> n;
bool isprime = 1;
for (int i = 2;i*i <= n;i++) {
    if (n % i == 0) isprime = 0;
}
cout << isprime << endl;

下列程式的時間複雜度是?

\( \Omicron ( \sqrt{n} ) \)

練習

int n;
cin >> n;
int a[n], pref[n];
for (int i = 0;i < n;i++) {
    cin >> a[i];
    pref[i] = a[i];
    if (i > 0) pref[i] += pref[i-1];
}
int ans = 0;
for (int i = 0;i < n;i++) {
    for (int j = 0;j < i;j++) {
        ans = max(ans, pref[i] - pref[j]);
    }
}
cout << ans << endl;

下列程式的時間複雜度是?

\( \Omicron ( n^2 ) \)

練習

int n;
cin >> n;

int cnt = 0;
while (n > 0) {
    cnt++;
    n /= 2;
}
cout << cnt << endl;

下列程式的時間複雜度是?

\( \Omicron ( \log n ) \)

練習

int n, k;
cin >> n >> k;
int a[n], pref[n];
for (int i = 0;i < n;i++) {
    cin >> a[i];
    pref[i] = a[i];
    if (i > 0) pref[i] += pref[i-1];
}
int ans = 0, ind = 0;
for (int i = 0;i < n;i++) {
    while (ind <= i && pref[i] - pref[ind] + a[ind] > k) {
        ind++;
    }
    ans += i - ind + 1;
}
cout << ans << endl;

下列程式的時間複雜度是?

\( \Omicron (n) \)

練習

int n;cin >> n;
bool isprime[n];
for(int i=1;i<=n;i++) isprime[i]=1;
for(int i=2;i<=n;i++){
    for(int j=2*i;j<=n;j+=i) isprime[j]=0;
}
for(int i=2;i<=n;i++) if(isprime[i]) cout << i << '\n';

下列程式的時間複雜度是?

\( \Omicron (n \log n) \)

時間複雜度有時候需要依靠一些性質才能算出!

沒那麼簡單!

STL

deck

By peter940324

deck

  • 902