9/21 複賽培訓[0]
327 王培軒
這份簡報大量參考去年(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 \)
演算法應該要在題目滿足條件的情況下,輸出正確的答案。
競賽程式與一般軟體工程師做的事情有些不同:
要怎麼做...
執行時間、空間消耗的估算
給你一個陣列\(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) \)
時間複雜度有時候需要依靠一些性質才能算出!
沒那麼簡單!