<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>競程 on Ray's Blog</title><link>https://chaoray.github.io/tags/%E7%AB%B6%E7%A8%8B/</link><description>Recent content in 競程 on Ray's Blog</description><generator>Hugo</generator><language>zh-TW</language><copyright>2026 Chao Ray. All rights reserved. 本站文章版權所有，未經授權禁止轉載</copyright><lastBuildDate>Thu, 23 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://chaoray.github.io/tags/%E7%AB%B6%E7%A8%8B/index.xml" rel="self" type="application/rss+xml"/><item><title>O(n)預處理組合數</title><link>https://chaoray.github.io/posts/notes/on%E9%A0%90%E8%99%95%E7%90%86%E7%B5%84%E5%90%88%E6%95%B8/</link><pubDate>Thu, 23 Jul 2026 00:00:00 +0000</pubDate><guid>https://chaoray.github.io/posts/notes/on%E9%A0%90%E8%99%95%E7%90%86%E7%B5%84%E5%90%88%E6%95%B8/</guid><description>&lt;p&gt;由於 $C^n_r$ 是階乘，直接硬算會算很久，因此預先處理來快速算出組合數尤為重要。&lt;br&gt;
想法是利用模反元素，將除以 $k!$ 改成乘以 $k!$ 的模反元素。這個方法預處理的時間複雜度為 $O(N)$，之後就能用 $O(1)$ 查詢。&lt;br&gt;
步驟：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先開一個陣列紀錄 $0! \sim n! \pmod M$ 的值&lt;/li&gt;
&lt;li&gt;計算 $n! \pmod M$ 的模逆元，再開一個陣列紀錄 $k! \sim 0!$ 的模逆元。&lt;br&gt;
只要先求出 $(k!)^{-1}$ ，就可以利用 $(k!)^{-1} = (k + 1)!^{-1} \times (k + 1) \pmod M$ 來由大到小得出所有階乘的模逆元。&lt;/li&gt;
&lt;li&gt;查詢時，只要利用 $C^n_k = n! \times (k!)^{-1} \times ((n - k)!)^{-1} \pmod M$ 在 $O(1)$ 得出。&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define MOD 1000000007LL
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define MAXN 200005
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#define ll long long
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;namespace&lt;/span&gt; std;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ll &lt;span style="color:#a6e22e"&gt;qpow&lt;/span&gt;(ll a, ll b) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ll res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; a &lt;span style="color:#f92672"&gt;%=&lt;/span&gt; MOD;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;while&lt;/span&gt; (b &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (b &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; res &lt;span style="color:#f92672"&gt;*&lt;/span&gt; a &lt;span style="color:#f92672"&gt;%&lt;/span&gt; MOD;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; a &lt;span style="color:#f92672"&gt;=&lt;/span&gt; a &lt;span style="color:#f92672"&gt;*&lt;/span&gt; a &lt;span style="color:#f92672"&gt;%&lt;/span&gt; MOD;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; b &lt;span style="color:#f92672"&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; res;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ll &lt;span style="color:#a6e22e"&gt;inverse_mod&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; a) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; qpow(a, MOD &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ll fact[MAXN], inv_fact[MAXN];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;precompute_combination&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fact[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; inv_fact[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; MAXN; i&lt;span style="color:#f92672"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fact[i] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; fact[i &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#f92672"&gt;*&lt;/span&gt; i &lt;span style="color:#f92672"&gt;%&lt;/span&gt; MOD;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; inv_fact[MAXN &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; inverse_mod(fact[MAXN &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; MAXN &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;; i &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;; i&lt;span style="color:#f92672"&gt;--&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; inv_fact[i] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; inv_fact[i &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;] &lt;span style="color:#f92672"&gt;*&lt;/span&gt; (i &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;) &lt;span style="color:#f92672"&gt;%&lt;/span&gt; MOD;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ll &lt;span style="color:#a6e22e"&gt;nCr&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; n, &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; r) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (r &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; r &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; n) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; fact[n] &lt;span style="color:#f92672"&gt;*&lt;/span&gt; inv_fact[r] &lt;span style="color:#f92672"&gt;%&lt;/span&gt; MOD &lt;span style="color:#f92672"&gt;*&lt;/span&gt; inv_fact[n &lt;span style="color:#f92672"&gt;-&lt;/span&gt; r] &lt;span style="color:#f92672"&gt;%&lt;/span&gt; MOD;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Suffix Array</title><link>https://chaoray.github.io/posts/notes/suffix-array/</link><pubDate>Thu, 23 Jul 2026 00:00:00 +0000</pubDate><guid>https://chaoray.github.io/posts/notes/suffix-array/</guid><description>&lt;h2 id="後綴是甚麼"&gt;後綴是甚麼？&lt;/h2&gt;
&lt;p&gt;比方說字串 &lt;code&gt;S = banana&lt;/code&gt;，S的所有後綴就是：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;banana
anana
nana
ana
na
a
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;將這些後綴排序後：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;a
ana
anana
banana
na
nana
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Suffix Array就是將字串的每個後綴進行排序後，紀錄該後綴開頭index的陣列：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; SA[N];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SA[i]; &lt;span style="color:#75715e"&gt;// 表示順序第i個後綴的開頭index
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果 &lt;code&gt;SA[3] = 0&lt;/code&gt; ，表示字典序第 4 小的後綴是從 &lt;code&gt;S[0]&lt;/code&gt; 開頭的，也就是 &lt;code&gt;banana&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;例題：算出 &lt;code&gt;s = &amp;quot;aba&amp;quot;&lt;/code&gt; 的 SA 陣列&lt;/p&gt;
&lt;details class="alert alert-spoiler"&gt;
&lt;summary class="alert-heading"&gt;
&lt;span class="alert-icon"&gt;&lt;svg class="octicon octicon-eye-closed mr-2" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true" fill="currentColor"&gt;&lt;path d="M8.22 1.754a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368ZM8.22 1.754A12.078 12.078 0 0 1 1.164 8c.978 2.168 2.726 3.987 4.908 5.246a.75.75 0 0 0 .684 0C8.932 11.987 10.68 10.168 11.658 8 10.68 5.832 8.932 4.013 6.752 2.754a.75.75 0 0 0-.684 0L2.772 5.326a.75.75 0 0 0-.126.167L8.22 1.754ZM1.5 8c0-.825.342-1.613.95-2.233A12.078 12.078 0 0 0 1.164 8c.978 2.168 2.726 3.987 4.908 5.246a.75.75 0 0 0 .684 0C8.932 11.987 10.68 10.168 11.658 8 10.68 5.832 8.932 4.013 6.752 2.754a.75.75 0 0 0-.684 0C3.896 4.013 2.148 5.832 1.17 8ZM8 10.5a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5ZM8 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/span&gt;ans&lt;/summary&gt;
&lt;div class="alert-content"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SA[&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/details&gt;&lt;h2 id="怎麼找出-suffix-array-"&gt;怎麼找出 Suffix Array ？&lt;/h2&gt;
&lt;p&gt;暴力法就是把所有後綴抓出來，然後進行排序。顯然這個方法的時間複雜度是 $O(N^2\log N)$ (別忘了比較兩個字串要 $O(N)$)。&lt;/p&gt;</description></item><item><title>模反元素</title><link>https://chaoray.github.io/posts/notes/%E6%A8%A1%E5%8F%8D%E5%85%83%E7%B4%A0/</link><pubDate>Tue, 30 Sep 2025 00:00:00 +0000</pubDate><guid>https://chaoray.github.io/posts/notes/%E6%A8%A1%E5%8F%8D%E5%85%83%E7%B4%A0/</guid><description>&lt;p&gt;又稱&lt;strong&gt;模倒數&lt;/strong&gt;、&lt;strong&gt;模逆元&lt;/strong&gt;，簡稱$MMI$或$inv$&lt;/p&gt;
&lt;p&gt;如果$a$跟$n$互質&lt;/p&gt;
&lt;p&gt;那一定有一個$b$，讓$(a \times b) \mod n = 1$&lt;br&gt;
或$(a \times b - 1)$可以整除$n$&lt;/p&gt;
&lt;p&gt;這時候$b$就是$a \mod n$的模反元素&lt;/p&gt;
&lt;p&gt;而且$b + kn, k \in Z$&lt;br&gt;
$b + kn$都是$a \mod n$的模反元素&lt;/p&gt;
&lt;h2 id="用途"&gt;用途&lt;/h2&gt;
&lt;p&gt;在求$a \div b \mod p$時，如果$a$、$b$太大無法直接相除&lt;/p&gt;
&lt;p&gt;需要把$\div b$替換成$\times c$，並使$a \div b \equiv a \times c \pmod p$&lt;/p&gt;
&lt;p&gt;這樣就可以拆成$(a \mod p) \times (c \mod p)$&lt;br&gt;
而這個$c$就是模反元素&lt;/p&gt;
&lt;p&gt;處理溢位時尤為好用&lt;/p&gt;
&lt;h2 id="舉例"&gt;舉例&lt;/h2&gt;
&lt;p&gt;$3$、$11$互質&lt;br&gt;
$inv = 4$&lt;br&gt;
$3 \times 4 \mod 11 = 1$&lt;/p&gt;
&lt;p&gt;所以根據定義：&lt;br&gt;
$4 + 11k = 4, 15, 26 ...$&lt;br&gt;
$3 \times 15 \mod 11 = 1$&lt;br&gt;
$3 \times 26 \mod 11 = 1$&lt;br&gt;
$...$&lt;br&gt;
$3 \times (4 + 11k) \mod 11 = 1, k \in Z$&lt;/p&gt;</description></item></channel></rss>