1. 程式人生 > 其它 >「筆記」數論做題記錄

「筆記」數論做題記錄

人沒有回憶是無法活下去的喲 目錄

建議配合數論相關複習食用。

會不斷更新的。

BSGS

按著下面這個部落格刷的,我就不寫了。(太懶了

BSGS例題及題解

尤拉定理

P2155 [SDOI2008] 沙拉公主的困惑

根據歐幾里得演算法的這麼個式子 \(\gcd(x,y) = \gcd(x+ky,y)\)

那麼,如果 \(y \mid x\)\(x\) 以內與 \(y\)

互質的數的個數就是 \(\varphi (y) \frac{x}{y}\)(是一個倍數關係)。

所以這題答案為

\[\frac{n!}{m!} \varphi(m!) \]

\(\varphi (m!)\) 其實是可以遞推的。

  • 如果 \(m\) 是質數,\(\varphi (m!) = \varphi((m-1)!) \times (m-1)\)
  • 如果 \(m\) 不是質數,\(\varphi (m!) = \varphi((m-1)!) \times m\)

那麼對於前面的那個分數,都知道當 \(n \ge mod\) 並且 \(m \ge mod\) 時是不能直接算的,因為 \(n!\)

中的 \(mod\)\(m!\) 中的 \(mod\) 有可能會抵消掉。

於是在遞推階乘的時候可以特判一下,當 \(i=mod\) 時直接令 \(n!=(n-1)!\)

在計算的時候再判斷一下,只有當 \(\left\lfloor \frac{n}{mod} \right\rfloor = \left\lfloor \frac{m}{mod} \right\rfloor\) 不滿足時答案為 \(0\)

P4139 上帝與集合的正確用法

顯然質數大於模數,根據尤拉定理我們知道

\[a^p \equiv a^{p \% \varphi(m)+\varphi(m)} \pmod m \]

遞迴處理即可,就做完了,複雜度 \(O(\text{能過})\)

,(好像是 \(\log\) 級別?)

CF906D Power Tower

求尤拉函式寫錯了調半天/wul

做法和上個題一樣。

但是尤拉降冪的寫法我們還是需要注意,一定要嚴格遵循下列公式:

\[a^p = \begin{cases} a^c, & c < \varphi(m) \\ a^{c \% \varphi(m) + \varphi(m)}, & otherwise \end{cases} \bmod b \]

原因是當 \(\gcd(a,b) \neq 1\) 時,\(a^{\varphi(m)} \equiv 1 \pmod m\) 不一定成立。

具體實現可以在快速冪中處理:

int Pow(int x, int p, int mod) {
    int res = 1;
    while(p) {
        if(p & 1) {
            res = res * x;
            if(res >= mod) res = res % mod + mod; // 尤拉公式
        }
        x = x * x;
        if(x >= mod) x = x % mod + mod; // 尤拉公式
        p >>= 1;
    }
    return res;
}

P3934 [Ynoi2016] 炸脖龍 I

挺水的一道 Ynoi。

上面那題應該算這題的弱化版。

與上面那題的區別是模數不固定和帶修。

模數最大為 \(2 \times 10^7\) 直接線篩即可,帶修可以分塊或者樹狀陣列,實測他們的實際速度差不多。

這裡鳴謝 @NaCly_Fish 的寫法,可以判斷指數與模數的大小關係,以便遵守尤拉公式。()

struct node { int sum; bool flag; };
node Pow(int x, int p, int mod) {
    node res = (node){1, false};
    if(x >= mod) x %= mod, res.flag = true;
    while(p) {
        if(p & 1) {
            res.sum *= x;
            if(res.sum >= mod) {
                res.flag = true;
                res.sum %= mod;
            }
        }
        x = x * x;
        if(x >= mod) {
            res.flag = true;
            x %= mod;
        }
        p >>= 1;
    }
    return res;
}

node Solve(int l, int r, int p) {
    int x = a[l] + tag[pre[l]]; // 分塊
//    int x = Query(l); // 樹狀陣列
    if(p == 1) return (node){0, true};
    if(x == 1) return (node){1, false};
    if(l == r) return x < p ? (node){x, false} : (node){x % p, true};
    node res = Solve(l + 1, r, phi[p]);
    if(res.flag) res.sum += phi[p];
    return Pow(x, res.sum, p);
}

P3747 [六省聯考 2017] 相逢是問候

發現一個點修改多次只後就相當於 \(c^{c^{c^{...}}} \bmod p\),那個 \(a_i\) 就被忽略掉了。大約是 \(\log p\) 次。

所以考慮暴力修改,然後維護修改次數最小值。

但是這樣複雜度是 \(O(n \log^3 n)\)。 (線段樹 + 尤拉降冪 + 快速冪)

會被卡的很慘。

所以這題的正確姿勢是,預處理快速冪。

假設求 \(x^c\),因為 \(p\) 只有 \(10^8\),所以 \(c = c / 10000 + c \% 10000\),所以可以分別預處理這兩部分,計算的時候直接合並可以做到 \(O(1)\)

此時總複雜度 \(O(n \log^2 n)\)

擴充套件中國剩餘定理

P4774 [NOI2018] 屠龍勇士

真是一道既浪費了時間又玩崩了心態的好題呢。

題意就是解形如 \(b_ix \equiv a_i \pmod {p_i}\) 的同餘方程組。

1、假設已經得到了前面 \(i-1\) 個方程的解 \(ans\)
2、設 \(M = \text{lcm}(p_1,p_2,...,p_{i-1})\),則對於任意整數 \(x\)\(ans +xkM\) 是前 \(i-1\) 個方程的通解;
3、想得到前 \(i\) 個方程的解,就要滿足 \(b_i(ans+xM) \equiv a_i \pmod {p_i}\),移項得。
4、\(b_iM x \equiv a_i - b_i ans \pmod {p_i}\)
5、顯然可以用擴歐,直接轉化成 \(Ax+By = C\) 求解即可。

\[(b_iM)x + (p_i)y = (a_i - b_i ans) \]

然後注意的一點是有很多地方會爆 long long,注意加上龜速乘。