多項式,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,...\),其生成函式為
舉幾個例子:
-
若 \(a_{i}=從\ i\ 個球裡選出\ 0\ 個球的方案數\),則有 \(f_1(x)=1+x+x^2+x^3+x^4+...\);
-
若 \(a_{i}=從\ i\ 個球裡選出\ 1\ 個球的方案數\),則有 \(f_2(x)=0+x+2x^2+3x^3+4x^4+...\);
-
若 \(a_{i}=i\ 種糖果,每種有無限個,分給\ \text{Alice}\ 和\ \text{Bob}\ 的方案數\),則有 \(f_3(x)=0+x+2^{2}x^2+3^{2}x^3+4^{2}x^4+...\)。
好了,這就是生成函式的定義。但是現在你肯定會問,這東西有啥用呢?
小學我們就學過,這種有無限項相加的式子可以用“錯位相減”之類的辦法化成一個有限的表達方式。
那麼我們就試試生成函式是否同樣可以:
確實可以。即使它看起來很反常識,但這就是將一個無窮序列“濃縮”起來的表示方式。
類似地,還有\(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}\)。
最後總方案數的生成函式就是:
而 \(\frac{1}{(1-x)^2}\) 的意義可以參考例題二,也就是兩個集合內都有無限個元素 \(1,2,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\)」的函式?很簡單:
驗證一下,發現確實符合我們的要求。那麼程式碼也能很輕鬆的寫出來了。
不過由於這題需要取模,所以需要求逆元。如果模擬上式的計算,時間複雜度是 \(\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;
}