多項式

Avalaunch發表於2024-10-17

多項式,OI的魅力,OIer的噩夢。

多項式

這個大家應該都會。

對於式子 \(\sum\limits_{i=0}^{k}a_{i}x^i\),且 \(a_k \ne 0\),那麼我們稱它是關於 \(x\)\(k\) 次多項式。\(k\) 為次數。

就是這麼簡單

生成函式

定義:對於序列 \(a_0,a_1,a_2,a_3,...\),其生成函式為

\[f(x)=a_{0}+a_{1}x+a_{2}x_{2}+a_{3}x^{3}+... \]

舉幾個例子:

  1. \(a_{i}=從\ i\ 個球裡選出\ 0\ 個球的方案數\),則有 \(f_1(x)=1+x+x^2+x^3+x^4+...\)

  2. \(a_{i}=從\ i\ 個球裡選出\ 1\ 個球的方案數\),則有 \(f_2(x)=0+x+2x^2+3x^3+4x^4+...\)

  3. \(a_{i}=i\ 種糖果,每種有無限個,分給\ \text{Alice}\ 和\ \text{Bob}\ 的方案數\),則有 \(f_3(x)=0+x+2^{2}x^2+3^{2}x^3+4^{2}x^4+...\)

好了,這就是生成函式的定義。但是現在你肯定會問,這東西有啥用呢?

小學我們就學過,這種有無限項相加的式子可以用“錯位相減”之類的辦法化成一個有限的表達方式。

那麼我們就試試生成函式是否同樣可以:

\[\begin{aligned} f_1(x)&=\sum_{i=0}^{\infty}x^i\\ x f_1(x)&=\sum_{i=1}^{\infty}x^i\\ (1-x)f_1(x)&=1\\ \therefore f_1(x)&=\frac{1}{1-x}\\ \\ f_2(x)&=\sum_{i=0}^{\infty}i x^i\\ xf_2(x)&=\sum_{i=0}^{\infty}i x^{i+1}=\sum_{i=1}^{\infty}(i-1)x^i\\ (1-x)f_2(x)&=\sum_{i=0}^{\infty}i x^i - \sum_{i=1}^{\infty}(i-1)x^i=\sum_{i=1}^{\infty}i x^i - \sum_{i=1}^{\infty}(i-1)x^i\\ &= \sum_{i=1}^{\infty}x^i=\sum_{i=0}^{\infty}x^i - 1\\ &= f_1(x)-1 = \frac{1}{1-x} - 1 = \frac{x}{1-x}\\ \therefore f_2(x)&=\frac{x}{(1-x)^2} \end{aligned} \]

確實可以。即使它看起來很反常識,但這就是將一個無窮序列“濃縮”起來的表示方式。

類似地,還有\(f_3(x)=\sum\limits_{i=0}^{\infty}i^{2}x^{i}=\frac{x^2+x}{(1-x)^3}\),請讀者自己嘗試推導。

順帶一提,無限項的式子可以濃縮,有限也可以。比如可以利用等比數列求和公式把 \(1+x+x^2+x^3+...+x^k\) 寫成 \(\frac{1-x^{k+1}}{1-x}\)

所以到底有啥用

別急嘛,接下來看幾個例題你就明白了。

例題 1:有一個多重集 \(A\),其中值為 \(i\) 的元素有 \(a_i\) 個。還有一個多重集 \(B\),其中值為 \(i\) 的元素有 \(b_i\) 個。問:多重集 \(C=A\cup B\) 中值為 \(i\) 的有多少個?

顯然,是 \(c_i=a_i+b_i\)。算出 \(A\)\(B\) 的生成函式然後兩式相加即可。

例題 2:還是剛剛的 \(A\)\(B\),你可以從兩集合內各取一個元素,然後將和扔進 \(C\)。問: \(C\) 中值為 \(i\) 的有多少個?

你想了一下,然後還是很快反應過來了——將兩多項式相乘即可。

那如果。。。我想取出 \(k\) 的倍數,或者不超過 \(k\) 個,那麼閣下又該如何應對?

例題 3:現在有 \(A,B,C,D\) 四種水果,每種都有無限個。現在要恰好取出 \(n\) 個水果,但水果 \(A\) 必須取偶數個,水果 \(B\) 必須取 \(5\) 的倍數個,水果 \(C\) 最多隻能取 \(4\) 個,水果 \(D\) 最多隻能取 \(1\) 個。問:方案數是多少?

首先考慮倍數怎麼辦。\(A\) 必須取 \(2\) 的倍數個,也就是說偶次項係數為 \(1\),奇次項係數為 \(0\)。即 \(A(x)=0+x^2+x^4+x^6+...\),不難得出 \(A(x)=\frac{1}{1-x^2}\)

同理可得 \(B(x)=0+x^5+x^{10}+x^{15}+...=\frac{1}{1-x^5}\)

此時,一條顯然的規律也出來了:\(\sum\limits_{i=0,d|i}^{\infty}x^i=\frac{1}{1-x^d}\)

然後再考慮「至多」,此時的你應該也能發現,這就是上面說的有限項數的函式。

比如,\(C(x)=1+x+x^2+x^3+x^4\),利用公式寫成 \(\frac{1-x^5}{1-x}\)

同理,\(D(x)=1+x=\frac{1-x^2}{1-x}\)

最後總方案數的生成函式就是:

\[A(x)\times B(x)\times C(x)\times D(x)=\frac{1}{1-x^2}\times\frac{1}{1-x^5}\times\frac{1-x^5}{1-x}\times\frac{1-x^2}{1-x}=\frac{1}{(1-x)^2} \]

\(\frac{1}{(1-x)^2}\) 的意義可以參考例題二,也就是兩個集合內都有無限個元素 \(1,2,3,...\),然後每個集合選一個出來,再求和。

因此你就可以透過它的意義來還原多項式:

\[\frac{1}{(1-x)^2}=1+2x+3x^2+4x^3+... \]

解釋:\(0=0+0\)\(1=0+1=1+0\)\(2=0+2=1+1=2+0\)\(...\)

是不是很神奇?那麼複雜的問題,它的答案就是 \(n+1\)

不信?那你可以隨意拿幾個數試試哦。

洛谷P2000 拯救世界

不用多說,就是剛剛那題的加強版。建議先手動推一推。

最後你會發現答案是 \(\frac{1}{(1-n)^5}\),也就是選 \(5\) 個非負整數,使得和為 \(n\) 的方案數。這個東西就是小學學的插板法,\(n\) 個蘋果分給 \(5\) 個小朋友,可以有小朋友沒有,方案數是 ${n+5-1 \choose 5-1}={n+4 \choose 4}=\frac{(n+1)(n+2)(n+3)(n+4)}{24} $。

別急,再看看資料範圍——呃?這題還卡普通高精乘,看來得用 \(\text{NTT}\) qwq。

不過你用 Ruby 寫倒也不是不行

拉格朗日插值法

眾所周知,在平面直角座標系中,\(k\) 個橫座標互不相同的點就可以唯一確定一個 \((k-1)\) 次函式。這一點在程式碼上可以用高斯消元來解決。那麼就來看看這個題:洛谷P4781 【模板】拉格朗日插值

這時候我們看了眼資料範圍:

遺憾地發現高斯消元過不去了。

由於這題並不需要解出函式,只需求出 \(f(k)\) 的值,所以就可以引入一個新東西:拉格朗日插值法。

這個方法的思想就是,對每個點 \(i\) 求出一個函式 \(f_i\),滿足將 \(x_i\) 帶入可以返回 \(y_i\),但是將別的 \(x_j\) 帶入都會返回 \(0\)。這樣一來,把 \(k\) 帶入每個函式 \(f_i\),返回值加起來,就能得到 \(f(k)\)。這是因為你求出了一個函式 \(f(x)=f_1(x)+f_2(x)+...+f_n(x)\),滿足 \(f(x_i)=y_i\),也就是說 \(f(x)\) 就是原函式。(聰明的你這時也一定發現了,這個思想和中國剩餘定理有著異曲同工之妙)

那麼問題是如何構造一個「將 \(x_i\) 帶入可以返回 \(y_i\),但是將別的 \(x_j\) 帶入都會返回 \(0\)」的函式?很簡單:

\[f_i(x)=y_i \prod_{i\ne j} \frac{x-x_j}{x_i-x_j} \]

驗證一下,發現確實符合我們的要求。那麼程式碼也能很輕鬆的寫出來了。

不過由於這題需要取模,所以需要求逆元。如果模擬上式的計算,時間複雜度是 \(\mathcal{O}(n^2\log p)\)

觀察上式,發現可以每輪單獨記錄分子之積和分母之積,因此列舉完 \(j\) 再算總分母的逆元即可。時間複雜度 \(\mathcal{O}(n^2+n\log p)\)

點選檢視程式碼
#include <bits/stdc++.h>
using namespace std;
const int N = 2e3 + 5, MOD = 998244353;
int n, k, x[N], y[N], ans;
inline int madd(int x, int y) { return x + y >= MOD ? x + y - MOD : x + y; }
inline int msub(int x, int y) { return madd(x, MOD - y); }
inline int mmul(int x, int y) { return 1ll * x * y % MOD; }
inline int qpow(int x, int y) { int res = 1, t = x % MOD;
    while (y) { if (y & 1) res = mmul(res, t);
    t = mmul(t, t); y >>= 1; }
    return res; }
inline int mdiv(int x, int y) { return mmul(x, qpow(y, MOD - 2)); }

int main()
{
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
    {
        scanf("%d%d", x + i, y + i);
        if (k == x[i])
        {
            cout << y[i] << endl;
            return 0;
        }
    }
    for (int i = 1; i <= n; i++)
    {
        int bdiv = 1, div = 1;
        for (int j = 1; j <= n; j++)
            if (i != j)
            {
                bdiv = mmul(bdiv, msub(k, x[j]));
                div = mmul(div, msub(x[i], x[j]));
            }
        ans = madd(ans, mmul(y[i], mdiv(bdiv, div)));
    }
    cout << ans << endl;
    return 0;
}

[省選聯考 2022] 填樹

相關文章