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

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

  • 1,368