LeeShoWdian
      • 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
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • 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
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Help
Menu
Options
Engagement control Make a copy 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
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • 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
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    --- type: slide slideOptions: transition: fade; --- <style> .reveal .slides { text-align: left; font-size:28px; } </style> # random --- * 要怎麼random(產生亂數) * hash * 更多 random 題目 ---- ## 產生亂數 ---- ## 產生亂數 亂數?很簡單啊,大一程式設計就有教 ```cpp! rand(); srand(seed); ``` 但真的好嗎? ---- 在某些系統上 rand() 回傳範圍為 [$[0, ?]$](https://cplusplus.com/reference/cstdlib/RAND_MAX/#:~:text=This%20value%20is-,library%2Ddependent,-%2C%20but%20is%20guaranteed) $?$為一個數值,根據library or 系統決定 解決方法: - rand()拼成很多次很大的數字 - 用 mt19937 :D 以下會用 mt19937 實作隨機 ---- 在數學意義上並沒有真正的亂數,因此都只能用時間種子或者是怪怪的公式去假裝亂數 所以我們今天使用的是時間種子 ```cpp chrono::steady_clock::now().time_since_epoch().count() ``` 那記得使用這個要引入標頭檔 ```cpp #include<chrono> ``` 這是一個單位以 ms 來計算的時間亂數 ---- 分析 ```cpp chrono::steady_clock::now().time_since_epoch().count() ``` 首先 $steady\_clock$ 是一個單調的時鐘 然後 $now()$ 就是指現在的時間 接著 $time\_since\_epoch()$ 是指 現在獲取的 $now$ 到時間元年的間隔 最後 $count()$ 當然就是指有幾個間隔 *時間元年 1970/01/01 ---- 再來是產生器,我們會使用到的是 mt19937 什麼是mt19937呢,背後支持的數學演算法是梅森旋轉算法,可以使得在一個範圍內有隨機分布。 那要怎麼產生呢? ```cpp mt19937 變數名稱(亂數種子); ``` 所以我們的定義就會變成 ```cpp mt19937 mt(chrono::steady_clock::now().time_since_epoch().count()); ``` ---- 那我們就可以開始利用mt了 那因為mt是我們的產生器,我們還需要給他一個分布的範圍 ```cpp uniform_int_distribution<> dis(0, 1e9); ``` 那他的預設值就是int 如果今天要用小數點的話就分別是以下 ```cpp uniform_int_distribution<int> 分布變數名稱(最小值, 最大值); uniform_real_distribution<double> 分布變數名稱(最小值, 最大值); ``` ---- 所以最後就會這樣寫出東西 ```cpp #include<iostream> #include<random> #include<chrono> using namespace std; void solve(){ mt19937 mt(chrono::steady_clock::now().time_since_epoch().count()); uniform_int_distribution<> dis(0, 1e9); cout<<dis(mt)<<endl; } int main(){ solve(); return 0; } ``` ---- ## Shuffle random標頭檔下有shuffle函式 ```cpp shuffle(arr,arr+n,mt);//開頭,結尾,亂數產生器 ``` 跟sort的用法一樣,直接把你的arr全部打亂。 --- ## 算數學時間 ---- ## 簡單的練習 題目有 $T$ 筆測資,每筆測資你的程式會有 $p$ 的機率答對,並且你做了 $k$ 次取最好的,請問你 AC 的機率是多少 ---- 題目有 $T$ 筆測資,每筆測資你的程式會有 $p$ 的機率答對,並且你做了 $k$ 次取最好的,請問你 AC 的機率是多少 - 一筆測資對的機率 $\rightarrow p$ - 單筆測資答錯:猜了 k 次全部都錯,機率是 $(1 − p)^k$ - 單筆測資答對:$1 − (1 − p)^k$ - 全部答對:$(1 − (1 − p)^k)^T$ ---- ## 生日悖論 假設一年有 365 天,班上有 $n$ 個人,有任兩個人生日相同的機率是多少? Answer : ||$1-\frac{P^{365}_n}{365^n}$|| ||![image](https://hackmd.io/_uploads/rycnubA7kl.png =350x)|| ---- hash 的成功率跟這個悖論有關,附上[連結](https://zh.wikipedia.org/zh-tw/%E7%94%9F%E6%97%A5%E5%95%8F%E9%A1%8C),有興趣可以看! --- ## 不一樣的 Hash ---- ## 以前教過的hash 在字串課教過 rolling hash,可以讓你把一個字串的子字串壓成一個數字 $h(s_1,s_2 . . . s_n) = (s_1 × C^{n−1} + s_2 × C^{n−2} + · · · + s_n)$ $mod$ $M$ ---- ## 以前教過的hash - 一樣的子字串,拿去做hash,出來的值一定一樣 - 但是一樣的 hash 值,映射回來的子字串**不一定**一樣 - 什麼會影響碰撞的機率? ---- ## 例題 : 矩陣相乘 給你 $N*N$ 的矩陣 $A,B,C$,問你 $A \times B$ 是否等於 $C$ ? $N \le 10000$ ---- 暴力算矩陣乘法複雜度為 $O(n^3)$,就目前已知的計算矩陣乘法複雜度一定炸開,因此可以考慮對矩陣去做 hash ! ##### ~~什麼!!!矩陣可以拿來hash!!?~~ ---- ## 秉持 Hash 的精神,把矩陣 Hash 掉! 以前教過的 hash 可以把一個 「子字串」 or 「子區間」 hash 成一個數值,再去判斷兩者是不是一樣 如果這時候可以把矩陣 Hash 成「某個東西」的話,好像就很好判斷$AB = C$ 了? 設 $h$ 函數為可以把某矩陣 Hash 之後的變成某個東西的函數,所以要滿足: $h(AB) = h(C)$ 所以接下來要想個辦法算出 $h(AB)$ 和 $h(C)$.... ---- 對於以前學過的子區間 Hash , 可以展開成以下 matrix 形式 設 $R = \left[\begin{matrix} c_0 \\ c_1 \\ : \\ c_n\\ \end{matrix}\right]$,$\left[\begin{matrix} a_0 & a_1 & ... & a_n\\ \end{matrix}\right] \times R = hash$ 值 子區間可以看成 $1 \times N$ 的 matrix ,對於每一項,乘以他對應的 base ,而得到 $1 \times 1$ 的 hash 值 那我們是不是也可以把一個矩陣 ($N \times N$ 的matrix) 壓成更小的矩陣 (?) ---- 因此考慮.... $\left[\begin{matrix} a_{00} & a_{10} & ... & a_{n0}\\ a_{01} & a_{11} & ... & a_{n1}\\ : & : & ... & :\\ : & : & ... & :\\ a_{0n} & a_{1n} & ... & a_{nn}\\ \end{matrix}\right] \times R = \left[\begin{matrix} hash_0 \\ hash_1 \\ : \\ hash_n\\ \end{matrix}\right]$ 這樣做可以把一個 $N \times N$的矩陣 hash 成 $N\times 1$ 的小矩陣了 因此問題變成 $(AB)R = CR$ ,交換一下矩陣計算順序 $\rightarrow ABR = CR$ $\rightarrow A(BR) = CR$ 這樣計算的複雜度為 $O(n^2)$ ---- 前面好像都沒講到 $R$ 矩陣裡面的數值具體要塞什麼? 先別急,再觀察一個性質 - 如果 $AB = C$,則不論 $R$ 是什麼,等號一定成立 - 如果 $AB \neq C$,則不論 $R$ 是什麼,等號「不一定」成立 有這個性質可以幹嘛? ||可以 random!!|| ---- 讓 $R$ 裡面所有的元素全部都是亂數生成的 考慮 $AB \neq C$ 的情況,思考一下會發現,等號「成立」的情況機率很低,直接去算 $A(BR)=CR$ 好像很大機率會過! 不對啊!等號「成立」怎麼辦 $\rightarrow$ ||多做幾次!!|| ---- 多做幾次,讓WA的機率越乘越低,是 random 演算法的精神之一! ```cpp! while(time--){//做個 t 次,不要超過複雜度就好 1.隨機生成R矩陣 2.算A(BR) 3.算CR 4.如果ABR != CR -> "NO!!!!!" 5.如果ABR == CR -> 再做一次 } 做t次做完了,都沒問題 -> "YEESSSSSSS!!" ``` ---- 這裡我們學到了「二維Hash」,「生成隨機數把東西映射到其他東西(?)」的技巧,下面會再提更多 hash 的例子! ---- ## 成雙成對 給妳一個長度為 $n$ 的序列 $a_1, a_2, ... ,a_n$,給你 $q$ 筆詢問,每筆詢問給你 $[l,r]$ 問你 $[l,r]$ 區間內是否每一種數字都出現偶數次, $1 \le n,q \le 10^6$ $a_i \le 2^{31} -1$ ---- 不可能 $O(nq)$ 暴力去算,太白癡了 但我們好像學過根號算法? 複雜度 $O(n \sqrt n)$,好像還是不會過 ---- 這時候就要用隨機來~~唬爛~~了! ---- 透過觀察,會發現一個好的區間 $[l,r]$,滿足$a_l$ $\oplus ...$ $\oplus$ $a_r = 0$ ex: ```cpp! 9, 1, [3, 5, 3, 5], 2 ``` 為什麼呢?因為相同的數字透過 Xor 的性質,兩兩互相打架抵銷成 0 ---- 但是也有情況 Xor 會爛掉 - Xor 的好情況: $a$ $\oplus$ $a =0$ - Xor 的不夠好情況 $1$ $\oplus$ $2$ $\oplus$ $3 =0$ 因此要避免這種情況發生,這時就要用到隨機ㄌ ---- 可以選擇把每個元素透過隨機打到 long long 範圍的任意數字, 由於我們把值域範圍從 「$2^{31}-1$」 打到 「$2^{64}-1$」 左右,使碰撞的機率降低,在這樣的序列下去找好的區間,$1$ $\oplus$ $2$ $\oplus$ $3 =0$ 的情況發生機率極低。 其實隨機就這樣,很唬爛,看起來超玄,但會過 :/ ---- ## K的倍數 這時題目變成... 給妳一個長度為 $n$ 的序列 $a_1, a_2, ... ,a_n$,給你 $q$ 筆詢問,每筆詢問給你 $[l,r]$ 問你 $[l,r]$ 區間內是否每一種數字都出現 $K$ 的倍數次, $1 \le n,q \le 10^6$ ---- 概念一樣,把所有元素打到任意一個隨機數,再去找好的區間 這時限制變成,每種數字都出現 $K$ 的倍數次,怎麽做? ---- 上一題當中,對於同一種元素,我們讓他兩兩打架,打到最後讓他消失不見 那可以讓他們$k$$k$打架(?) ,一樣讓他們打起來,有兩種方法: 1. 設計一個 $\oplus_k$,代表 $k$ 進制的 xor 2. 用相加的,同一種元素讓他們加起來為0 顯然 1. 很好懂但很難實作,讓我們講講2. ---- 用相加的,我們假設一個區間裡面有 $k$ 個 $a$,我們可以把 $(k-1)$ 個 $a$ 打到 $+x$,第 $k$ 個 $a$ 設定成 $(k-1) \times (-x)$ , 這樣可以使得這段區間的 $a$ 相加為 0 因此可以這樣構造新的序列: |序列| $c$|$a$|$a$|$c$|$c$|$b$|$c$|$b$|$b$|$a$| |---|----|---|---|---|----|---|---|---|----|---| |打到的數字|$+z$|$+x$|$+x$|$+z$|$-2z$|$+y$|$+z$|$+y$|$-2y$|$-2x$| 這樣就只要算區間和為零的子區間有多少就好了,因為是一個long long範圍的隨機數,所以「區間和為零但不是一個好的區間」的機率會非常小 --- 休息一下~ --- ## 讓你覺得「蛤?為什麼這樣做會AC」的例題們 * 眾數 * 最近點對 ---- ## 眾數 絕對眾數的定義:數字出現次數嚴格超過長度的一半 ---- 題目 be like : 給你長度為 $N$ 的序列,$q$ 筆詢問 每次詢問給出區間 $[l,r]$ ,詢問裡面的區間絕對眾數是誰? ---- 你會發現,在區間裡面戳一個數字,它會是區間絕對眾數的機率會有$\frac 1 2$ 所以我們只要戳30次 這樣連戳30次都不是眾數的機率是 ${\frac 1 2}^{30}$ 那要怎麼確認一個數字是不是區間絕對眾數呢? ---- 把每個數字的index記錄下來 然後使用二分搜去算它在此區間有幾個數字,就可以知道它是不是區間絕對眾數 因此複雜度是 $O(30 Q log N)$ ---- ## 變化題 給你一個長度為 $n$ 的 arr ,求出一個 MOD 讓這個 arr 有絕對眾數 要取模誒 那他怎麼可能可以隨機? 還真可以。 因為在 MOD 完之後他會是絕對眾數,因此你任選一個數字,它取模完會是眾數的機率是 $\frac 1 2$ 所以隨機挑選兩個數字,兩個都是眾數的機率是 $\frac 1 4$ ,然後枚舉 $|x-y|$ 的質因數 當成模數去計算即可。 ---- ## 分析 一次取到兩個都是眾數的機會是 $\frac 1 4$ 也就是說不是的機率是 $\frac 3 4$ 那我只需要 ${\frac 3 4}^T$ 就可以保證會是對的。 ---- ## 最近點對 給你平面上 $N$ 個點,對於任意 $(i,j)$, 點 $i$ 和點 $j$ 的歐幾里德距離最小值是多少? ---- 以前有教過分治的算法,一直分左邊分右邊然後blablabla.... 但如果你有實作過的話,會發現最近點對分治超難寫,那我們試試隨機! ---- - 假設現在有 $i-1$ 個點在平面上,而且知道前 $i-1$ 個點的最近距離為 $d$ - 如果距離變短,那最近點對的其中一個點一定是 $i$ - $i$ 周圍畫一個半徑為 $d$ 的圓內有其他點 - 但是要檢查半徑為 $d$ 的圓內有沒有其他點太難了 QQ ---- - 退而求其次,我們找到一些可能跟它距離小於 $d$ 的點 - 把整個平面切成 $(\frac{d}{2})$ × $(\frac{d}{2})$ 的網格 - 檢查所有 $i$ 所在的格子和周圍 8 格和再往外一圈共 25 格裡的點 - 如果找到距離小於 $d$ 的點,就把網格重畫 ; 否則把 $i$ 直接加進它在的那個格子裡 ![image](https://hackmd.io/_uploads/ryu0JGAX1g.png =600x) ---- 聽起來,我們這時想到的做法會是: - 先把兩個點放在平面上,以這個點對當做目前的最近點對,距離為 $d$ ,並用這個 $d$ 在平面上分割網格 - 對於第 $3$~$n$ 的點$i$,檢查點 $i$在網格上的附近25個點,如果有點並且這個點跟點 $i$ 可以更新 $d$: - 就:用這個新的最近點對重新畫網格 - 否則:放進網格內 算算看複雜度 ---- - 每個格子內最多只有 1 個點 => 最多只要檢查 25 個點 - 每次重畫格子要花 O(i) 的時間,不然加入只要花 O(1) 的時間(用 hash table) - 這樣總時間需要考慮重畫格子、放進方格的機率,大約是 $\sum$加入第 $i$ 個點花的時間 $=\sum(p_i × O(i) + (1 − p_i) × O(1))$ - $p_i$ = 第 $i$ 個點要重畫格子的機率 但測資一定非常嚴格,一定會構造要你一直重畫格子的測資,因此會退化成 $O(n^2)$ ---- 但如果我們把點都 random_shuffle 呢? 既然現在 random 了,那複雜度一定會小於等於 $O(n^2)$ ,接下來就來算算看 random 後重新畫方格的機率 $p_i$ ---- 其實重新畫方格的機率就是 $O(\frac{1}{i})$,因此在shuffle之後複雜度會是: $\sum(p_i × O(i) + (1 − p_i) × O(1)) = O(n)$ 因此我們期望 $O(n)$ 就可以做完了 ---- ## 一些細節 1. 因為有些點座標會有負數,所以要事先把座標搬到第一象限 ```cpp! int mnx=1e18,mny=1e18; for(auto [x,y]:a){ mnx=min(mnx,x); mny=min(mny,y); } for(auto& [x,y]:a){ x-=mnx; y-=mny; } ``` 2. 為了好好分割網格,你可能會砸 map ,但是在值域很大 (ex:1e9,1e16)的時候還是乖乖做分治,不然map會炸掉QQ 3. ~~如果不信任 map 的話,也可以自己寫一個 hash~~ --- [練習題單 ](https://vjudge.net/contest/676813) 唬爛吧!

    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