chrislaiisme
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
# 111學年度上學期進階班期末考題解 ## 哥德巴赫猜想(偽) `tag: prime number, 梗題` 給你一數$N$ 把$N$拆成多個質數相加 --- 不知道哪個時候想到的題目 反正當時想到就想出成梗題 --- ### $1\%:\ N \in prime\ number$ 既然$N$自己就是質數 那就輸出他就好了 :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; int main() { // IO; LL T; cin >> T; while(T -- ) { LL N; cin >> N; cout << N << endl << 1 << endl; } } ``` ::: `Time Complexity:` $O(T)$ `Space Complexity:` $O(1)$ --- ### $14\%:\ 1 < N \leq 20$ 可以直接把 $2 \sim 20$ 的答案列出來 | $N$ | $ans$ | $N$ | $ans$ | | ---- | ------ | ---- | ------ | | $2$ | $2*1$ | $12$ | $2*6$ | | $3$ | $3*1$ | $13$ | $13*1$ | | $4$ | $2*2$ | $14$ | $2*7$ | | $5$ | $5*1$ | $15$ | $3*5$ | | $6$ | $2*3$ | $16$ | $2*8$ | | $7$ | $7*1$ | $17$ | $17*1$ | | $8$ | $2*4$ | $18$ | $2*9$ | | $9$ | $3*3$ | $19$ | $19*1$ | | $10$ | $2*5$ | $20$ | $2*10$ | | $11$ | $11*1$ | | | 然後套一堆`if`就可以了 :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; int main() { // IO; LL T; cin >> T; while(T -- ) { LL N; cin >> N; if(N == 2) { cout << 2 << endl << 1 << endl; } if(N == 3) { cout << 3 << endl << 1 << endl; } if(N == 4) { cout << 2 << endl << 2 << endl; } if(N == 5) { cout << 5 << endl << 1 << endl; } if(N == 6) { cout << 3 << endl << 2 << endl; } if(N == 7) { cout << 7 << endl << 1 << endl; } if(N == 8) { cout << 2 << endl << 4 << endl; } if(N == 9) { cout << 3 << endl << 3 << endl; } if(N == 10) { cout << 2 << endl << 5 << endl; } if(N == 11) { cout << 11 << endl << 1 << endl; } if(N == 12) { cout << 2 << endl << 6 << endl; } if(N == 13) { cout << 13 << endl << 1 << endl; } if(N == 14) { cout << 2 << endl << 7 << endl; } if(N == 15) { cout << 3 << endl << 5 << endl; } if(N == 16) { cout << 2 << endl << 8 << endl; } if(N == 17) { cout << 17 << endl << 1 << endl; } if(N == 18) { cout << 2 << endl << 9 << endl; } if(N == 19) { cout << 19 << endl << 1 << endl; } if(N == 20) { cout << 2 << endl << 10 << endl; } } } ``` ::: `Time Complexity:` $O(T)$ `Space Complexity:` $O(1)$ --- ### $20\%:\ 1 < N \leq 10^4,\ N \in even\ number$ 從題目可以得知,較小的偶數可以確定符合這個猜想 所以在這個測資點,可以把$N$拆成兩個質數(除了$N=2$) 記得要特判$N=2$ 而要怎麼去確定一個數字是否為質數呢 ```cpp= inline bool is_prime(LL n) { for(LL i = 2; i * i <= n; i ++ ) { if(n % i == 0) { return 0; } } return 1; } ``` 這個方法可以$O(\sqrt{n})$算出$n$是否為質數 :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; inline bool is_prime(LL n) { for(LL i = 2; i * i <= n; i ++ ) { if(n % i == 0) { return 0; } } return 1; } int main() { // IO; LL T; cin >> T; while(T -- ) { LL N; cin >> N; if(N == 2) { cout << 2 << endl << 1 << endl; continue; } for(LL i = 2; i < N; i ++ ) { LL a = i, b = N - i; if(is_prime(a) && is_prime(b)) { cout << a << " " << b << endl; cout << 1 << " " << 1 << endl; break; } } } } ``` ::: `Time Complexity:` $O(TN\sqrt{N})$ `Space Complexity:` $O(1)$ --- ### $(1\%) + 14\% + 20\% + 25\% = 60\% :\ 1 < N \leq 10^4$ 一個數如果不是偶數,那他就是奇數(廢話) 那我們可以把$N$分成兩種情況來看: $N$為偶數: 直接代$20\%$的code $N$為奇數: 那有一個$N$為奇數的話,可以寫成$3 + (N - 3)$ 且$3$為質數,$N - 3$為偶數 接著就可以用$N - 3$去代$15\%$的code(除了$N=3 or N=5$) 記得$N=2\ or\ N=3\ or\ N=5$時要特判 這樣就可以同時解掉$9\%,\ 15\%$和$35\%$的側資點 照理來說$1\%$的側資點不會被解掉 只是因為我把那個側資點的$T$設有夠小($20$) 加上你只要去判他是不是質數就能拿到這$1\%$了 所以我分數就直接送下去了 :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; inline bool is_prime(LL n) { for(LL i = 2; i * i <= n; i ++ ) { if(n % i == 0) { return 0; } } return 1; } int main() { // IO; LL T; cin >> T; while(T -- ) { LL N; cin >> N; if(N == 2) { cout << 2 << endl << 1 << endl; continue; } if(N == 3) { cout << 3 << endl << 1 << endl; continue; } if(N == 5) { cout << 5 << endl << 1 << endl; continue; } bool odd = 0; if(N % 2 == 1) { odd = 1; N -= 3; } for(LL i = 2; i < N; i ++ ) { LL a = i, b = N - i; if(is_prime(a) && is_prime(b)) { if(odd) cout << 3 << " "; cout << a << " " << b << endl; if(odd) cout << 1 << " "; cout << 1 << " " << 1 << endl; break; } } } } ``` ::: `Time Complexity:` $O(TN\sqrt{N})$ `Space Complexity:` $O(1)$ --- ### $1\% + 14\% + 20\% + 25\% + 40\% = 100\% :\ 1 < N \leq 2^{31} - 1$ 定理:當有一個$N\ge 2$時,可以寫成$2m+3n(m, n \in \mathbb{Z^+})$ 證明: 一數$N$可以被分成兩種狀態,奇數or偶數 當$N$為偶數: $N$可以被寫成$2a$,則$m=a,\ n=0$ 當$N$為奇數: $N$可以被寫成$2a+1=2(a-1)+3$,則$m=a-1,\ n=1$ $\mathbb{Q.E.D.}$ 因為$n=0$在題目的輸出中是合法的 所以也不用特判,直接輸出即可 這就是這題梗的地方 (而且程式碼有夠簡單) :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; int main() { // IO; LL T; cin >> T; while(T -- ) { LL N; cin >> N; if(N % 2) { cout << 2 << " " << 3 << endl; cout << N / 2 - 1 << " " << 1 << endl; } else { cout << 2 << endl; cout << N / 2 << endl; } } } ``` ::: `Time Complexity:` $O(T)$ `Space Complexity:` $O(1)$ --- --- ## 兩元三元 `tag: quadratic equation, 成年禮` 有兩元,有三元 一個兩元 + 一個三元 = 一個七元 給你一個數字$N$ 有兩元$m$個跟三元$n$個 將這堆錢的幣值最大化 求有幾種不重複的$(m, n)$,可以得到$N$的總價錢 --- 高二成年禮玩大地遊戲的時候想到的題目 想了想發現還滿水的 --- ### $5\% :\ 1 \leq N \leq 10$ 直接把答案列出來就可以了 | N | ans | N | ans | | --- | --- | ---- | --- | | $1$ | $0$ | $6$ | $2$ | | $2$ | $1$ | $7$ | $1$ | | $3$ | $1$ | $8$ | $1$ | | $4$ | $1$ | $9$ | $2$ | | $5$ | $0$ | $10$ | $2$ | 然後用陣列就可以了 :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; int main() { // IO; LL T; cin >> T; LL arr[10] = {0, 1, 1, 1, 0, 2, 1, 1, 2, 2}; while(T -- ) { LL N; cin >> N; cout << arr[N - 1] << endl; } } ``` ::: `Time Complexity:` $O(T)$ `Space Complexity:` $O(N)$ --- ### $5\% + 20\% = 25\% :\ 1 \leq N \leq 10^3$ 可以去模擬有幾個兩元跟三元 用雙層迴圈去模擬 當還沒氧化前的總和就$>N$就可以跳下一次迴圈 :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; int main() { // IO; LL T; cin >> T; while(T -- ) { LL N; cin >> N; LL ans = 0; for(LL i = 0; ; i ++ ) { if(i * 2 > N) break; for(LL j = 0; ; j ++ ) { if(i * 2 + j * 3 > N) break; LL tmp = min(i, j); LL num = tmp * 7 + (i - tmp) * 2 + (j - tmp) * 3; if(num == N) ans ++ ; } } cout << ans << endl; } } ``` ::: `Time Complexity:` $O(TN^2)$ `Space Complexity:` $O(1)$ --- ### $5\% + 20\% + 35\% = 60\% :\ 1 \leq N \leq 10^6$ 題目說要將幣值最大化 也就是要將能換成七元的錢都換成七元 當我們這樣做時 我們會發現最後沒有被換成七元的一定是兩元或三元其中一種(或是都沒剩) 那這樣題目就可以另寫成: 求$N = 7m+2n\ or\ N = 7m+3n$的$(m, n)$有幾組不重複解$(m, n \in \mathbb{Z^+})$ 那我們可以去對$m$做窮舉,找$n$的可能情況 但要注意一件事 當$n = 0$時,$(m, n)$會被同時算在$7m+2n\ \&\ 7m+3n$中 所以這時候的答案要$-1$ 那什麼時候$n$會出現$=0$的情況呢 就是當$N = 0\ (mod\ 7)$的時候 :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; int main() { // IO; LL T; cin >> T; while(T -- ) { LL N; cin >> N; LL ans = 0; for(LL i = N; i >= 0; i -= 7) { ans += (i % 2 == 0); ans += (i % 3 == 0); } if(N % 7 == 0) ans -- ; cout << ans << endl; } } ``` ::: `Time Complexity:` $O(TN)$ `Space Complexity:` $O(1)$ --- ### $5\% + 20\% + 35\% + 40\% = 100\% :\ 1 \leq N \leq 2^{31} - 1$ 要想 <b style="color: lime;">AC</b> 就要動用到一點數學常識了 先以$7m+2n=N$為例 $7m+2n = 7(m-2)+2(n+7) = 7(m-4)+2(n+14)$ $=\cdots=7(m-2k) + 2(n+7k)\ (k \in \mathbb{Z^+})$ 然後因為$(m, n \in \mathbb{Z^+})$,所以要滿足$(m-2k) \ge 0$ 我們可以先找到$m$最大的解,然後找有幾組的$(m-2k) \ge 0$,也就是$m/2+1$組 先以$7m+3n=N$也是一樣的道理 然後記得當$N = 0\ (mod\ 7)$的時候要把答案$-1$ :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; int main() { // IO; LL T; cin >> T; while(T -- ) { LL N; cin >> N; LL ans = 0, a, b; a = N / 7, b = N % 7; while(b % 2) a -- , b += 7; if(a >= 0) ans += a / 2 + 1; a = N / 7, b = N % 7; while(b % 3) a -- , b += 7; if(a >= 0) ans += a / 3 + 1; if(N % 7 == 0) ans -- ; cout << ans << endl; } } ``` ::: `Time Complexity:` $O(T)$ `Space Complexity:` $O(1)$ --- --- ## 數之數織 `tag: DFS, pruning` 給你一個數織,完成他 --- 當初想說除了數獨跟八皇后還有什麼比較好出的DFS題 然後就想到了這個東西 去查才知道這個鬼東西叫數織 題外話 我這題想了好幾天 一直改想法,一直把題目`debuff` 生測資生到快崩潰 所以我要先在試前做一個大膽的猜測 ### <font style="color: red; font-size: 50px">大膽的猜測</font> 這題應該不會有人(除了$frankie$)在競賽中<b style="color: lime;">AC</b> 然後我先猜$frankie$會<font>WA</font>至少$20$次 --- ### $1\%:\ N = 1$ 因為題目保證測資皆有解 所以很直觀的,直接輸出$1$就可以了 :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; int main() { // IO; LL T; cin >> T; while(T -- ) { LL N, lft, up; cin >> N >> lft >> up; cout << 1 << endl; } } ``` ::: `Time Complexity:` $O(T)$ `Space Complexity:` $O(1)$ --- ### $14\% :\ N = 2$ 因為題目保證測資皆有解 那在$N=2$的情況下只會有$1$跟$2$這兩種答案 然後$ans=2$的情況也就只有$1\ 1\ 1\ 1$這種 其他都是$ans=1$ 然後如果你想要那$1\%$也可以再判$N=1$ :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; int main() { // IO; LL T; cin >> T; while(T -- ) { LL N, a, b, c, d; cin >> N >> a >> b >> c >> d; if(a*b*c*d == 1) cout << 2 << endl; else cout << 1 << endl; } } ``` ::: `Time Complexity:` $O(T)$ `Space Complexity:` $O(1)$ --- ### $1\% + 14\% + 45\% = 60\% :\ N \leq 5$ 就純$DFS$ 但因為題目有限制格中只有一個數字 所以不用一格一格去塗黑 可以先由同一個方向塗$N$條黑格 然後塗完再用另一個方向去檢驗這個解法是否可行 這個實作可以用一個二維$bool$陣列來做 有塗黑就$1$,反之則$0$ 然後記得把變數開在全域 喔然後格中有可能會出現$0$這個數字 為了避免重複計算答案 遇到$0$就直接跳下一條黑格來塗 :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; constexpr LL maxN = 15; LL N, ans; LL lft[maxN], up[maxN]; bool mat[maxN][maxN]; inline void DFS(LL pos = 0) { if(pos == N) { for(LL i = 0; i < N; i ++ ) { LL cnt = 0, tmp = 0; // tmp: 0 = not yet in tile, 1 = in tile, 2 = over tile for(LL j = 0; j < N; j ++ ) { if(tmp == 0 && mat[j][i]) tmp ++ ; if(tmp == 1 && !mat[j][i]) tmp ++ ; if(mat[j][i] && tmp == 2) return; cnt += mat[j][i]; } if(cnt != up[i]) return; } ans ++ ; return; } if(lft[pos] == 0) { DFS(pos + 1); return; } for(LL i = 0; i + lft[pos] - 1 < N; i ++ ) { for(LL j = i; j < i + lft[pos]; j ++ ) mat[pos][j] = 1; DFS(pos + 1); for(LL j = i; j < i + lft[pos]; j ++ ) mat[pos][j] = 0; } } int main() { // IO; LL T; cin >> T; while(T -- ) { ans = 0; memset(mat, 0, sizeof(mat)); cin >> N; for(LL i = 0; i < N; i ++ ) cin >> lft[i]; for(LL i= 0; i < N; i ++ ) cin >> up[i]; DFS(); cout << ans << endl; } } ``` ::: `Time Complexity:` $O(TN^2)$ `Space Complexity:` $O(N^2)$ --- ### $1\% + 14\% + 45\% + 40\% = 100\% :\ N \leq 10$ 這題如果真的要優化的話 肯定有很多種方法 反正我這邊丟我的方法 跟$60\%$一樣,先對一個方向塗黑條 但跟$60\%$不一樣的地方在於 要一邊塗一邊用另一個方向去判斷解法是否可行 大概優化的想法在這邊 細節的話我也講一下好了 除了$lft$跟$up$,還要設一個檢查陣列$chk$跟一個計數陣列$arr$ 其中$chk$是來表示「第$i$欄是否還可以被放置黑格」 並且其中的元素分成三種值: $0:$都行,$1:$這欄的下一格一定要塗黑,$-1:$這欄不能再被塗黑 $chk$是來表示「第$i$欄被放了幾個黑格」 預設都為$0$ 所以這題其實可以不用二為陣列去實作 接下來只要一邊塗黑條一邊去動態看這樣塗是否合法 就可以完成了 然後注意一些細節($0$的出現,有些欄沒被塗完,$DFS$回上層要把資料回歸 $\cdots$) 大概就能<b style="color: lime;">AC</b>了 :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" #define mem(x) memset(x, 0, sizeof(x)) using namespace std; using LL = long long; constexpr LL maxN = 15; LL N; LL up[maxN], lft[maxN], arr[maxN], chk[maxN], ans = 0; // chk[i] : 1 = put, 0 = all ok, -1 = don't put inline void DFS(LL pos = 0) { if(pos == N) { for(LL i = 0; i < N; i ++ ) { if(arr[i] != up[i]) return; } ans ++ ; return; } if(lft[pos] == 0) { for(LL i = 0; i < N; i ++ ) { if(chk[i] == 1) return; } DFS(pos + 1); return; } for(LL i = 0; i + lft[pos] - 1 < N; i ++ ) { bool bln = 1; for(LL j = 0; j < N; j ++ ) { if(i <= j && j <= i + lft[pos] - 1) { if(chk[j] < 0) { bln = 0; break; } } else if(chk[j] > 0) { bln = 0; break; } } if(!bln) continue; for(LL j = i; j < i + lft[pos]; j ++ ) { arr[j] ++ ; if(arr[j] == up[j]) chk[j] = -1; else chk[j] = 1; } DFS(pos + 1); for(LL j = i; j < i + lft[pos]; j ++ ) { arr[j] -- ; if(arr[j]) chk[j] = 1; else chk[j] = 0; } } } inline void init() { mem(up); mem(lft); mem(arr); mem(chk); ans = 0; } int main() { // IO; LL T; cin >> T; while(T -- ) { init(); cin >> N; for(LL i = 0; i < N; i ++ ) cin >> lft[i]; for(LL i = 0; i < N; i ++ ) cin >> up[i]; DFS(); cout << ans << endl; } } ``` ::: `Time Complexity:` $O(TN^2)$ `Space Complexity:` $O(N)$ --- --- ## 長方形分配者—小駿 `tag: recursion, DP, matrix exponentiation, 小駿` 有一個寬為$1$且長為$N$的矩形 從這個矩形的長邊其中一端,一直切下「長為整數且大於1的長方形」,而最後不剩 有多少切法 --- 在寫$110$學科時想到的題目 是當時$pI$的簡化但又加強版 --- ### $5\%:\ 1 \leq N \leq 5$ 直接列出來 | N | ans | | --- | --- | | $1$ | $0$ | | $2$ | $1$ | | $3$ | $1$ | | $4$ | $2$ | | $5$ | $3$ | 然後用陣列 :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; int main() { // IO; LL T; cin >> T; LL arr[5] = {0, 1, 1, 2, 3}; while(T -- ) { LL N; cin >> N; cout << arr[N - 1] << endl; } } ``` ::: `Time Complexity:` $O(T)$ `Space Complexity:` $O(N)$ --- ### $5\% + 20\% = 25\%:\ 1 \leq N \leq 30$ 直接用遞迴模擬切掉的長度 當完整切完就可以回傳$1$ (你要用`if else`我也是沒差啦) 然後$N=1$要特判 :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; inline LL ans(LL n) { if(n == 0) return 1; LL r = 0; for(LL i = 2; i <= n; i ++ ) r += ans(n - i); return r; } int main() { // IO; LL T; cin >> T; while(T -- ) { LL N; cin >> N; if(N == 1) { cout << 0 << endl; continue; } cout << ans(N) << endl; } } ``` ::: `Time Complexity:` $O(T*2^N)$ `Space Complexity:` $O(1)$ --- ### $5\% + 20\% + 30\% = 55\%:\ 1 \leq N \leq 10^3$ 剛剛的`code`可以寫出以下遞迴式: $\large{f(n) = \begin{cases} 1 \qquad \qquad \qquad \qquad if\ \ n=0 \\ 0 \qquad \qquad \qquad \qquad if\ \ n=1 \\ \Sigma_{k = 2}^{n} f(n-k)\qquad else \\ \end{cases}}$ 因為我們可以從一端切下長度為$2 \sim N$的長方形 那這樣我們就可以用陣列存取重複的值 也就是用$DP$ 然後從這個側資點開始 答案會超過`long long`範圍 所以別忘了$mod\ 10^9+7$ :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; constexpr LL mod = 1e9 + 7; int main() { // IO; LL T; cin >> T; while(T -- ) { LL N; cin >> N; LL arr[N + 1]; memset(arr, 0, sizeof(arr)); arr[0] = 1; for(LL i = 1; i <= N; i ++ ) { for(LL j = 2; j <= i; j ++ ) { arr[i] = (arr[i] + arr[i - j]) % mod; } } cout << arr[N] << endl; } } ``` ::: `Time Complexity:` $O(T*N^2)$ `Space Complexity:` $O(N)$ --- ### $5\% + 20\% + 30\% + 35\% = 90\%:\ 1 \leq N \leq 10^6$ 我們再看一下剛剛的遞迴式: $\large{f(n) = \begin{cases} 1 \qquad \qquad \qquad \qquad if\ \ n=0 \\ 0 \qquad \qquad \qquad \qquad if\ \ n=1 \\ \Sigma_{k = 2}^{n} f(n-k)\qquad else \\ \end{cases}}$ 其中我們看到`else`那邊 $\large{f(n) = \Sigma_{k = 2}^{n} f(n-k)}$ 我們做一個神奇的操作,先列下這兩條式子 $f(n) \quad\;\;\, = f(n-2)+f(n-3)+f(n-4)+\cdots+f(2)+f(1)+f(0)$ $f(n-1) = \qquad\qquad\;\;\; f(n-3)+f(n-4)+\cdots+f(2)+f(1)+f(0)$ 我把兩式相減得 $f(n) - f(n - 1) = f(n - 2)$ 再移個項 $f(n) = f(n - 1) + f(n - 2)$ 太神奇了,這不就是費氏數列嗎 只是要記得$f(0) = 1 \ \&\ f(1) = 0$ (其實只要把前幾項列出來就能大概猜到了) 就直接給他$DP$砸下去 要建表或不建表都過得了所以沒差 要滾動或不滾動都過得了所以沒差 只是如果不滾動就要用$vector$,陣列會爆 別忘了$mod\ 10^9+7$ :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; constexpr LL mod = 1e9 + 7; int main() { // IO; LL T; cin >> T; while(T -- ) { LL N; cin >> N; vector<LL> vec(N + 1, 0); vec[0] = 1; for(LL i = 2; i <= N; i ++ ) vec[i] = (vec[i - 1] + vec[i - 2]) % mod; cout << vec[N] << endl; } } ``` ::: `Time Complexity:` $O(TN)$ `Space Complexity:` $O(N)$ --- ### $\color{red}{5\% + 20\% + 30\% + 35\% + 10\% = 100\%:\ 1 \leq N \leq 2^{31}-1}$ 為什麼上面那個那麼紅勒 因為這個側資點大概只有`frankie`解得出來 應該可以說是這次的防破台側資點 先給大家科普一下「矩陣快速冪」是什麼 把遞迴式寫成矩陣乘法式 之後藉由快速冪將矩陣乘法加速 最後省下一大堆時間的$DP$優化 整體可以看去年講義的[這個](https://hackmd.io/@fdhscpp110/matix_fast_pow) 反正這個側資點就是必須用這個優化才能過去 :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; template<typename T> using Vec = vector<T>; template<typename T> using Mat = Vec<Vec<T> >; constexpr LL mod = 1e9 + 7; inline Mat<LL> multi(Mat<LL> a, Mat<LL> b, LL x, LL y, LL z) { Mat<LL> ret(x, Vec<LL>(y, 0)); for(LL i = 0; i < x; i ++ ) { for(LL j = 0; j < y; j ++ ) { for(LL k = 0; k < z; k ++ ) { ret[i][j] = (ret[i][j] + a[i][k] * b[k][j]) % mod; } } } return ret; } inline Mat<LL> pwr(Mat<LL> a, LL b) { Mat<LL> r = {{1, 0}, {0, 1}}; for(; b; a = multi(a, a, 2, 2, 2), b >>= 1) { if(b & 1) r = multi(r, a, 2, 2, 2); } return r; } inline LL Fib(LL n) { Mat<LL> r = {{1}, {1}}, a = {{1, 1}, {1, 0}}; r = multi(pwr(a, n), r, 2, 1, 2); return r[0][0]; } int main() { // IO; LL T; cin >> T; while(T -- ) { LL N; cin >> N; if(N == 1) { cout << 0 << endl; continue; } if(N == 2) { cout << 1 << endl; continue; } cout << Fib(N - 3) << endl; } } ``` ::: `Time Complexity:` $O(TlgN)$ `Space Complexity:` $O(1)$ --- --- ## 更大堆的0與1 `tag: binary, 型態轉換, 卡記憶體, 11011111101010010` 給你$N$跟$K$ 再給$2^N-K$個由$0,\ 1$組成的長度為$N$的不重複字串 輸出$K$個跟這些字串不一樣的「由$0,\ 1$組成的長度為$N$的字串」 --- 某天我哥在跟我討論他出爛的某一題 我就在想能不能出個進階版然後讓他至少不是爛的 然後這題就出出來了 --- ### $0\%:$ 基本常識 & 注意事項 「由$0,\ 1$組成的長度為$N$的不重複字串」 這個東西總共有$2^N$種 這算是基本常識,也可用排列組合來解釋 反正就是有$N$位,每位有$2$種狀態 所以是$2^N$種 所以題目可以看成 把所有沒列出的狀態列出來 喔然後記得壓$IO$優化 --- ### $5\%:\ N = 3,\ K = 1$ $N=3$共有$8$種狀態: $000,\ 001,\ 010,\ 011,\ 100,\ 101,\ 110,\ 111$ 然後可以用`set`維護有哪些還沒出現過 你要用`if`我也是沒差但我懶 :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; int main() { IO; LL T; cin >> T; while(T -- ) { LL N, K; cin >> N >> K; set<string> st = {"000", "001", "010", "011", "100", "101", "110", "111"}; for(LL i = 0; i < 8 - K; i ++ ) { string str; cin >> str; st.erase(str); } for(auto &i : st) cout << i << endl; } } ``` ::: `Time Complexity:` $O(TN^22^N)$ `Space Complexity:` $O(2^N)$ --- ### $5\% + 15\% = 20\% :\ N \leq 10$ $N=10$共有$1024$種狀態 太多了列不出來 所以這個時候只能用迴圈一個一個生 可以發現這些字串其實就是$0 \sim 2^N-1$的二進位 所以可以寫一個函式把十進位轉為二進位 像這樣 ```cpp= inline string d_to_b(LL num) { string str; while(num) { str += (num & 1) + '0'; num >>= 1; } while(str.length() < N) str += '0'; reverse(str.begin(), str.end()); return str; } ``` 要注意的是要把前面不足的$0$補起來 然後求$2^N$可以用$pow(2,\ N)$這個函式 雖然不太好但因為$N$夠小所以還是準的 一樣用`set`維護有哪些還沒出現過 :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; LL N, K; inline string d_to_b(LL num) { string str; while(num) { str += (num & 1) + '0'; num >>= 1; } while(str.length() < N) str += '0'; reverse(str.begin(), str.end()); return str; } int main() { IO; LL T; cin >> T; while(T -- ) { cin >> N >> K; LL M = pow(2, N); set<string> st; for(LL i = 0; i < M; i ++ ) st.insert(d_to_b(i)); for(LL i = 0; i < M - K; i ++ ) { string str; cin >> str; st.erase(str); } for(auto &i : st) cout << i << endl; } } ``` ::: `Time Complexity:` $O(TN^22^N)$ `Space Complexity:` $O(2^N)$ --- ### $5\% + 40\% = 45\%:\ N \leq 18,\ K = 1$ 現在不能用`set`了,我有卡記憶體 但可以注意一件事,$K = 1$ 這代表剩一個沒有出現 那我們這邊再給一個小常識 「在所有排列中,所有位數出現$0\ or\ 1$的個數都是$2^{N-1}$」 就以$N=3$來說 $000,\ 001,\ 010,\ 011,\ 100,\ 101,\ 110,\ 111$ 第一位為$0$的有$4$個,第一位為$1$的有$4$個 第二位為$0$的有$4$個,第二位為$1$的有$4$個 第三位為$0$的有$4$個,第三位為$1$的有$4$個 所以我們可以去記「第$i$位為$0$的有幾個」 是$2^{N-1}$的話答案的第$i$位就是$1$ 反之就是$0$ :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; int main() { IO; LL T; cin >> T; while(T -- ) { LL N, K; cin >> N >> K; LL arr[N], M = pow(2, N); for(LL i = 0; i < M - K; i ++ ) { string str; cin >> str; for(LL i = 0; i < N; i ++ ) if(str[i] == '0') arr[i] ++ ; } for(auto &i : arr) cout << (i == pow(2, N - 1) ? '1' : '0'); cout << endl; } } ``` ::: `Time Complexity:` $O(TN2^N)$ `Space Complexity:` $O(N)$ --- ### $5\% + 15\% + 40\% + 40\% = 100\%:\ N \leq 18$ 現在不能用`set`了,我有卡記憶體 也不能用$K = 1$的方法了 那我也懶得想怎麼講的比較好懂,因為懂得都懂 所以直接講解法 可以把每個輸入的字串想像成二進位,並把這些轉成十進位 然後用一個長為$2^N$的`bool`陣列去存有那些出現過 最後找沒出現過的然後把十進位轉成二進為後輸出就可以了 大概就是 ```cpp= bool arr[pow(2, N)] = 全都0; while(bla bla bla) { cin >> str; LL num = 二進位轉十進位(str); arr[num] = 1; } for(LL i = 0, i < pow(2, N); i ++ ) if(!arr[i]) cout << 十進位轉二進位(i); ``` 所以還要再寫一個函式是二進位轉十進位 ```cpp= inline LL b_to_d(string str) { LL r = 0; for(LL i = str.length() - 1, tmp = 1; i >= 0; i -- , tmp *= 2) if(str[i] == '1') r += tmp; return r; } ``` 大概就是這樣 :::spoiler code ```cpp= #include<bits/stdc++.h> #define IO cin.tie(0) -> sync_with_stdio(0) #define endl "\n" using namespace std; using LL = long long; LL N, K; inline string d_to_b(LL num) { string str; while(num) { str += (num & 1) + '0'; num >>= 1; } while(str.length() < N) str += '0'; reverse(str.begin(), str.end()); return str; } inline LL b_to_d(string str) { LL r = 0; for(LL i = str.length() - 1, tmp = 1; i >= 0; i -- , tmp *= 2) if(str[i] == '1') r += tmp; return r; } int main() { IO; LL T; cin >> T; while(T -- ) { cin >> N >> K; LL M = pow(2, N); bool arr[M]; memset(arr, 0, sizeof(arr)); for(LL i = 0; i < M - K; i ++ ) { string str; cin >> str; arr[b_to_d(str)] ++ ; } for(LL i = 0; i < M; i ++ ) { if(!arr[i]) { cout << d_to_b(i) << endl; } } } } ``` ::: `Time Complexity:` $O(TN2^N)$ `Space Complexity:` $O(2^N)$

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully