14th Sep. 2020
來看《君の名は。》吧!
有\(N\)場會議,第\(i\)個會議起訖時間都是從\(s_i\)到\(t_i\)的。然而,只有一個會議室,且每一個會要不然不開,要不然完全開完。請問最多可以安排幾次兩兩不相撞的會議呢?
(\(N \leq 2\times 10^5, l_i, r_i \leq 10^9\))
怎麼樣拿才會最好?
怎麼樣拿才會最好?
怎麼樣拿才會最好?
怎麼樣拿才會最好?
若每次都選可以選的中,結束時間最小的,則這樣子的答案一定不會比任何其他選擇差。
你有一個機器和\(N\)個訂單,第\(i\)個訂單若完成,會得到\(w_i\)的錢,但是必須在\(d_i\)的時間前完成。若每一個工作要做的時間都是一時間單位,請問最大的獲益為何?
(\(N \leq 2 \times 10^5, d_i, w_i \leq 10^9\))
Why?????????
如果看截止日期最大的那一個,那就直接放呀(如果有多個不就選最大的那個嗎)
然後剩下的再和截止日次大的哪些一起考慮⋯⋯
Codeforces Subsequences
給定一個數字\(K\),請找一個最短的字串使得"codeforces"這個出現為那個字串的子序列至少\(K\)次。
(\(K \leq 10^{16}\))
Multiples of Length
你有一個長度為\(N\)的序列\(a_i\)。你的目標是想要讓\(a_i\)都等於\(0\)。你可以做最多三次這個運算:
可以證明一定做得到,\(N \leq 10^5, |a_i| \leq 10^9\)
Harmonious Graph
有一個\(N\)個點,\(M\)個邊的無向圖。一個圖稱為「和諧的」若且唯若對於所有的\(1 \leq l < m < r \leq N\),若點\(l\)能夠走到點\(r\),則點\(l\)就可以走到點\(m\)。請問我最少要加多少條邊才能讓圖變成和諧的呢?
(\(N, M \leq 2 \times 10^5\))
Array Splitting
給你一個長度為\(N\)的非嚴格遞增自序列\(a_i\),請將序列分為\(K\)個連續的區塊,使得
\(\sum_i^K \max(i) - \min(i)\)
最小。\(\max(i), \min(i)\)分別代表第\(i\)個區塊中的最大值和最小值。
Dynamic programming is both a mathematical optimization method and a computer programming method. The method was developed by Richard Bellman in the 1950s and has found applications in numerous fields, from aerospace engineering to economics."
--Wikipedia
1950年代由Richard Bellman提出
老闆喜歡的名稱(?)
斐波那契數列的定義如下:
\(a_0 = a_1 = 1\)
\(a_n = a_{n - 1} + a_{n - 2}\)
給你\(n\),請求\(a_n \pmod {10^9 + 7}\)?
斐波那契數列的定義如下:
\(a_0 = a_1 = 1\)
\(a_n = a_{n - 1} + a_{n - 2}\)
給你\(n\),請求\(a_n \pmod {10^9 + 7}\)?
int f(int n){
if(n <= 1) return 1;
return f(n - 1) + f(n - 2)
}
naïve 做法:\(O(\varphi^n)\),超爛
將之前的東西存起來!
const int M = 1e9 + 7;
int fib[1e5];
fib[0] = fib[1] = 1;
for(int i = 2; i < N; i++)
fib[i] = (fib[i - 1] + fib[i - 2]) % M;
\(O(n)\),快多了!
其實可以做到\(O(\log N)\),不過不是今天上課的範疇
你有\(N\)個東西,第\(i\)個東西有價值\(v_i\)和重量\(w_i\)且只有一個。但是,你的包包最多只能承受最多為\(W\)的重量。請問你的包包在重量限制內,最多可以攜帶多少的價值?
若\(\text{dp}[i][j]\)代表「若只用前\(i\)個東西,且重量已經最多用了\(j\),這樣拿到的價值最多可以為何」,則可以列出式子
\(\text{dp}[i][j] = \max(\text{dp}[i - 1][j], \text{dp}[i - 1][j - w_i] + v_i)\)
不拿第\(i\)個
拿第\(i\)個
for(int i = 0; i < N; i++){
for(int j = W - 1; j >= 0; j--){
dp[i][j] = max(dp[i - 1][j], dp[i][j - w[i]] + v[i]);
}
}
注意,\(j\)要倒著轉移!想想看,如果不是如此,會出現什麼問題呢?
每個物品都可以任意拿
for(int i = 0; i < N; i++){
for(int j = 0; j < W; j++){
dp[i][j] = max(dp[i - 1][j], dp[i][j - w[i]] + v[i]);
}
}
第\(i\)個物品可以拿\(c_i\)個
\(O(NW\log C)\)的解(二次方分拆):
給你兩個長度為\(N, M\)的序列\(A, B\),請找出一個字串\(S\)使得\(S\)是\(A\)的子序列也是\(B\)的子序列,且\(|S|\)最大。
(\(N, M \leq 10^3\))
\(X\)為\(Y\)的子序列若且唯若\(X\)可以透過\(Y\)刪減一些字元而其餘字元不改變其相對位置而得。
令\(\text{dp}[i][j]\)代表\(A\)的前\(i\)個字元和\(B\)的前\(j\)個字元所構成的最長共同子序列。則
\(\text{dp}[i][j] = \begin{cases}\max(dp[i - 1][j - 1] + 1,dp[i - 1][j], dp[i ][j - 1])&\;, A_i = B_j\\\max(dp[i - 1][j], dp[i ][j - 1])&\;, \text{else}\end{cases}\)
\(O(NM)\)
給定一個長度為\(N\)的序列\(a_i\),請求一個\(a\)的子序列,使得其非嚴格遞增且其長度最長。
(Subtask 1: \(N \leq 10^3\)、Subtask 2: \(N \leq 10^5\))
\(\text{dp}[i]\)為「結尾在\(i\)的地方的最長遞增子序列可以多長」
\(\text{dp}[i] = \max_{j < i \text{且} a_j < a_i}(\text{dp}[j] + 1)\)
\(O(N^2)\), Subtask 1 AC
之後就會學到可以用線段樹之類的東西優化,但是這裏教一個比較酷的方法:每次都lower_bound,就可以了!
\(O(N \log N)\), Subtask 2 AC
int arr[N];
vector<int> v;
v.resize(N + 1);
fill(v.begin(), v.end(), INF);
for(int i = 0; i < N; i++){
*lower_bound(v.begin(), v.end(), arr[i]) = arr[i];
}
return lower_bound(v.begin(), v.end(), INF) - v.begin();
之後就會學到可以用線段樹之類的東西優化,但是這裏教一個比較酷的方法:
\(O(N^2)\), Subtask 1 AC
給你一個長度為\(N\)的序列\(a_i\),請找到一組\(l \leq r\)使得\(\sum_l^r a_i\)最大。
(\(N \leq 10^5, |a_i| \leq 10^9\))
Colored Rectangles
有三種木棒對,塗成三種顏色,分別有\(R, G, B\),分別為\(r_1, r_2, \dots, r_R\)、\(g_1, g_2, \dots, g_G\)、\(b_1, b_1, \dots, b_B\)。現在,你可以重複做這個操作:
請問最大的總分數為何?
(\(N \leq 200, r_i, g_i, b_i \leq 2000\))