By 建國中學 賴昭勳
把序列切一半
遞迴處理(先假設做得到)
假設有兩個已排序好的序列,要怎麼有效率地將它們合併成一個?
1 | 3 | 5 | 8 | 9 |
---|---|---|---|---|
1 | 2 | 2 | 7 |
1
1
2
2
3
5
7
8
9
聽懂了ㄇ?(這張講師做好久ww
這樣有 O(logn)層
每層都是O(n)
所以就能O(nlogn)排序了!!
#include <iostream>
using namespace std;
void merge_sort(int a[], int l, int r) { //[l, r)
if (r - l <= 1) return;
int mid = (l + r) / 2;
merge_sort(a, l, mid);
merge_sort(a, mid, r); //thus, [l, mid) and [mid, r) are sorted
int sorted[r - l];
int li = l, ind = 0;
for (int ri = mid;ri < r;ri++) { //two pointers
while (li < mid && a[li] <= a[ri]) {
sorted[ind] = a[li];
ind++, li++;
}
sorted[ind] = a[ri];
ind++;
}
while (li < mid) { //insert remaining elements
sorted[ind] = a[li];
ind++, li++;
}
for (int i = 0;i < r - l;i++) a[i + l] = sorted[i];
}
int main() {
int n;
cin >> n;
int a[n];
for (int i = 0;i < n;i++) {
cin >> a[i];
}
merge_sort(a, 0, n);
for (int i = 0;i < n;i++) cout << a[i] << " ";
cout << endl;
}
這很容易有bug喔!有問題可以看這份!
可以說是全TIOJ最經典的題目(之一)了!
給你一個數列,問有多少組
符合
對於每個東西,問你右邊有幾個東西比他小,把那個數量加起來。
O(n^2) Naive 解...
廢話><....嗎?
有沒有發現這樣我就不用講很多dp 了XDD
有一個 n列m行 的正整數矩陣,要問你每ㄧ列的最大值,但你不知道矩陣長什麼樣子,只能詢問某一個位置的數值。保證每一列的最大值位置嚴格遞增。
直線上有 n < 10^5 個點,第 i 個點有位置pi,依速度 vi 做等速運動,令 d(i, j) 為第 i 個點跟第 j 個點在以後無限時間最短的距離,
求
P.S. 這題以後學資料結構再做也可以喔!
平面上有 n 個點,求任兩點之間最短距離。
答案會是 min(左, 右, 左右之間)
d
複雜度:
int solve(int n) {
if (n < 0) return 0;
else if (n <= 1) return 1;
else return solve(n - 1) + solve(n - 2) + solve(n - 3);
}
這樣的複雜度?
int solve(int n) {
int ans[n + 1];
ans[0] = 0;
for (int i = 1;i <= n;i++) {
ans[i] = ans[i - 1];
if (i > 1) ans[i] += ans[i - 2];
if (i > 2) ans[i] += ans[i - 3];
}
return ans[n];
}
0.定義
1.轉移方式 (aka 遞迴式)
2.邊界條件
dp[0][0] = a[0][0]
注意 j == 0 時不能從 dp[i - 1][j - 1] 轉移!
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n;
cin >> n;
int a[n][n], dp[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j<= i; j++) {
cin >> a[i][j];
}
}
for (int i = n - 1; i >= 0; i--) {
for (int j = 0; j<= i; j++) {
if (i < n - 1) {
dp[i][j] = a[i][j] + \
max(dp[i + 1][j], dp[i + 1][j + 1]);
} else {
dp[i][j] = a[i][j];
}
}
}
cout << dp[0][0] << endl;
return 0;
}
#include <cstdio>
inline short read() {
short num = 0;
char c = getchar_unlocked();
while (c < '0' || c > '9') {
c=getchar_unlocked();
}
while (c>='0' && c<='9') {
num *= 10;
num += c - '0';
c = getchar_unlocked();
}
return num;
}
void putint(short a) {
int d = 0;
char c[5];
while (a) {
c[d++] = '0' + a % 10;
a /= 10;
}
for (int i = d - 1;i >= 0;i--) putchar_unlocked(c[i]);
}
short dp[200];
int main() {
short n = read();
short ans = 0;
for (short i = 0; i < n; i++) {
for (int j = 0;j <= i;++j) {
dp[100 + j] = (dp[j] > (j ? dp[j - 1] : -1) ? dp[j] : dp[j - 1]) + read();
}
for (int j = 0;j <= i;++j) {
dp[j] = dp[100 + j];
ans = dp[j] > ans ? dp[j] : ans;
}
}
putint(ans);
return 0;
}
有 n 個東西,每個東西有重量 wi 和價值 pi,你有一個耐重 m 的背包,問在不超過耐重的前提下價值最多可以多少?
單純窮舉每個東西放與不放的話,複雜度是O(2^n)。
有沒有辦法減少可能的狀態數?
最後答案可以怎麼取得?
一種取法可以怎麼表示?
有沒有辦法減少可能的狀態數?有w
最後答案可以怎麼取得?
看每一種重量下最多能拿多少取max
一種取法可以怎麼表示?
有總重量和總價值兩個數值
dp[i][j] 代表考慮了前 個東西,總重量 時的最大價值。
這樣的話答案必為
怎麼轉移?
如果多加了一個東西,就可以更新到他現在考慮的那個東西的那個重量!
注意:這理論上不是真的多項式複雜度喔!(有值域項)
有 n 種東西,每個東西有重量 wi 和價值 pi,且每種東西都有無限供應。
你有一個耐重 m 的背包,問在不超過耐重的前提下價值最多可以多少?
有 n 個東西,每個東西有重量 wi 和價值 pi,且每種東西都可以切成任意大小塊。
你有一個耐重 m 的背包,問在不超過耐重的前提下價值最多可以多少?
給你一個正整數序列,問你最多可以從裡面選出幾個元素(不改變順序),使得這些元素嚴格遞增。
例如:7, 1, 2, 2, 5, 3, 4 的LIS 是
1, 2, 3, 4
假設第 項要選的話,我們一定希望那項之前選的個數越多越好。
如果讓 表示取了 為最後一個數字的LIS呢?
要怎麼轉移?
這要怎麼維護才不會O(n^2)?
(如果不用值域壓縮+BIT的話)
轉移:找到使 最大,且比
小的 ,去更新
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
int n;
cin >> n;
int a[n];
for (int i = 0;i < n;i++) cin >> a[i];
vector<int> lis;
for (int i = 0;i < n;i++) {
int ind = lower_bound(lis.begin(), lis.end(), a[i]) - lis.begin();
//lower bound: the iterator of the first element >= a[i]
if (ind == lis.size()) {
lis.push_back(a[i]);
} else {
lis[ind] = a[i];
}
}
cout << lis.size() << endl;
return 0;
}
池塘中有一隻青蛙在四塊石頭A、B、C、D之中跳來跳去。今青蛙由A起跳,每次跳到另一塊石頭,青蛙跳了n次後停在A的方法數有多少呢?
註:原題範圍很小,可以出到
並將答案模 1000000007
池塘中有 n 顆排成一列的石頭,每顆石頭上有一隻青蛙和一個數字 a[i]。
每一分鐘,所有在第 i 顆石頭上的青蛙會往右跳 a[i] 格到第 i + a[i]個石頭(一顆石頭上可能有多隻青蛙),如果a[i] + i >= n青蛙就會跳進池塘裡。
請問在 k 分鐘後有幾隻青蛙會在池塘裡?
From PCCA 2020
Ans:
由下到上有n 個平台,FHVirus 從第 1 個開始,每次可以往上跳 1~2個平台。給你每個平台的水平位置,請問跳到第 n 個平台最少的水平移動是多少?
你要在直線道路上架管線,管線由管線本身(?)和支柱組成。每段管線高度可為1或2(首尾高度皆必須為1),且有一個 01組成的序列,如果第 i 項為 1 代表第 i 公尺高度一定是2。管線每公尺要花 a 元,支柱每公尺 b 元,請問最小花費是多少? (n <= 10^5)
Hint:
給你 n*m 的矩陣,每個元素代表一單位空間,其中有些位置有障礙物。你必須選取一個沒有障礙物的正方形區塊。請問這個區塊最大的面積是多少?
本題有多筆測資!!!別像我當年一樣WA十遍 ;-;
有 r 對紅色棍子,g 對綠色,b 對藍色(不同對棍子長度不同)
每次可以取兩對顏色不同的棍子組成長方形,且一對棍子只能用一次。請問組完若干個長方形的最大面積總和是多少?
若
Hint
代表紅色取 個,綠色取 個,
藍色取 個的最大面積
Ans:
8e7 和 Jass 在玩一個遊戲:有一個正整數數列,兩人輪流把最左邊或最右邊的數字拿走,假設 8e7 先手,他跟 Jass 都使用最佳策略下分別可以拿幾分?