s*s 怎麼整天給我推薦神奇的多項式題,我又不會 ……
洛谷 4705
我感覺這題不是很好理解,我狠狠惡補了一波多項式知識。
當然主要原因還是我除了裸的多項式乘法以外壓根沒做過什麼多項式題,乘法以上的操作(求逆之類)都只寫過板子 ……
前置知識(這題要用 ln ):
(說實話我現在看我將近一年四個月以前寫的這些東西,感覺寫得並不好,很多地方沒說清楚,什麼時候有空了重新寫一下。)
來看這道題。根據題意可以直接列出答案的表示式:
\[ans_k=\frac^n\sum_^m (a_i+b_j)^k}
\]\(ans\) 理論上長度是無窮大,本題中只需要取前 \(t+1\) 項(相當於在模 \(x^\) 意義下)。
把它寫成生成函式的形式。生成函式僅僅是為了方便描述,把數列改寫成多項式的形式,自變數 \(x\) 和求得的值都沒有意義,我們要求的僅僅是每一項的係數。
\[ans=\sum_^\infin\frac^n\sum_^m (a_i+b_j)^k}
\]用二項式定理展開,然後做一些基本的變換。把一些可以直接算的常數放到左邊:
\[\begin
ans&=\frac\sum_^\infin x_k\sum_^n\sum_^m \sum_^k c_k^r\cdot a_i^r\cdot b_j^\\
&=\frac\sum_^\infin x_k\sum_^k \frac\cdot \sum_^n a_i^r\cdot \sum_^m b_j^\\
&=\frac\sum_^\infin k!\cdot x_k\sum_^k\sum_^n\frac\cdot\sum_^m\frac}\\
\end\]
觀察發現:
\[ans=a*b\cdot c
\]其中星號表示多項式卷積,點號表示多項式點積(對應位相乘)(下同),多項式 \(a\)、\(b\) 和 \(c\) 的定義如下:
\[a=\sum_^\infin\frac^a_i^rx^r}
\]\[b=\sum_^\infin\frac^b_i^rx^r}
\]\[c=\frac\sum_^\infin r!x^r
\]這三個多項式的長度和 \(ans\) 一樣都是無窮大。
注意到 \(c\) 可以直接計算,\(a\) 和 \(b\) 形式相似。因此可以把問題轉化成求形如下面這個的多項式,最後給每一項除以 \(r!\) 即可:
\[\begin
f&=\sum_^\infin\sum_^a_i^rx^r\\
&=\sum_^\sum_^\infin a_i^rx^r
\end\]
注意到第一層求和裡面的內容是乙個等比數列求和。因為可以給 \(x\) 指定任意乙個非 \(0\) 值,所以不妨認為 \(0,這樣這個無窮等比數列的和就是收斂的,極限是 \(0\) 。根據等比數列求和公式,變為:
\[f=\sum_^n \frac
\]但這樣還不夠。別忘了要求的不是和而是模 \(x^\) 意義下每一項的係數。上式可進一步變為:
\[\begin
f&=\sum_^n \frac\\
&=\sum_^n (1+\frac)\\
&=n-x\sum_^n\frac\\
&=n-x\sum_^n (\ln(1-a_ix))'\end\]
注意 \((\ln(a(x)))'\) 是把 \(x\) 作為自變數求導,所以要用一次鏈式法則。即:
\[(\ln(a(x)))'=\frac
\]別忘了求 \(\ln(1-a_ix)\) 要在模 \(x^\) 的意義下進行。
(我到這裡的時候以為做完了就直接把部落格發上去了 …… 五分鐘後突然想起來時間複雜度不太對)
因為導數的和等於和的導數,對數的和等於積的對數,所以:
\[\begin
f&=n-x\sum_^n (\ln(1-a_ix))'\\
&=n-x(\sum_^n \ln(1-a_ix))'\\
&=n-x(\ln(\prod_^n (1-a_ix)))'\end\]
求積可以用分治 + ntt 解決,時間複雜度 \(o(n\log^2 n)\) 。然後照著這個式子就能算出 \(f\) 。
這樣我們就把 \(a\) 和 \(b\) 算出來了。直接卷起來再點乘上 \(c\) 就是答案。
(等等這題好像並不是特別複雜,為什麼我做的時候糾結得要死 ……)
#include #include #include #include using namespace std;
namespace zyt
templateinline void write(t x)
typedef long long ll;
const int n = 1e5 + 10, p = 998244353;
int fac[n], finv[n];
int power(int a, int b)
return ans;
} int getinv(const int a)
namespace polynomial
for (int i = 0; i < n; i++)
rev[i] = ((rev[i >> 1] >> 1) | ((i & 1) << (lg2 - 1)));
} void ntt(int *const a, const int *const w, const int n)
}void mul(const int *const a, const int *const b, int *const c, const int n)
void _inv(const int *const a, int *const b, const int n)
static int x[len], y[len];
_inv(a, y, (n + 1) / 2);
int m = 1, lg2 = 0;
while (m <= n * 2)
m <<= 1, ++lg2;
init(m, lg2);
memcpy(x, a, sizeof(int[n]));
memset(x + n, 0, sizeof(int[m - n]));
memset(y + (n + 1) / 2, 0, sizeof(int[m - (n + 1) / 2]));
ntt(x, omega, m), ntt(y, omega, m);
for (int i = 0; i < m; i++)
y[i] = ((ll)y[i] * 2ll % p - (ll)x[i] * y[i] % p * y[i] % p + p) % p;
ntt(y, winv, m);
int invm = getinv(m);
for (int i = 0; i < n; i++)
b[i] = (ll)y[i] * invm % p;
} void inv(const int *const a, int *b, const int n)
void derivative(const int *const a, int *const b, const int n)
void integral(const int *const a, int *const b, const int n)
void ln(const int *const a, int *const b, const int n)
}int a[n], b[n], n, m, a[n], b[n], t;
void solve(const int *const a, const int l, const int r, int *const f)
int mid = (l + r) >> 1, *x = new int[r - l + 2], *y = new int[r - l + 2];
solve(a, l, mid, x), solve(a, mid + 1, r, y);
memset(x + mid - l + 2, 0, sizeof(int[r - mid]));
memset(y + r - mid + 1, 0, sizeof(int[mid - l + 1]));
mul(x, y, f, r - l + 2);
delete x;
delete y;
} void cal(const int *const a, const int n, int *const f)
void init()
int work() }
int main()
洛谷 P4705 玩遊戲
題目要求的是 sum n sum m a i b j x x in 1,t 利用二項式定理化式子,begin sum n sum m a i b j x sum n sum m sum x binoma i kb j x sum n sum m sum x frac frac x sum x fra...
洛谷P4705 玩遊戲
題目描述 題解 首先對於 k in 1,t 我們列出其答案的式子 ans k frac n sum m a i b j k 觀察分子的式子,把它用二項式定理展開 sum k sum n sum m k x a i xb j k sum k sum n frac sum m frac 這兩個括號裡的式...
洛谷1067 多項式輸出
一元 n 次多項式可用如下的表示式表示 其中,aixi稱為 i 次項,ai 稱為 i 次項的係數。給出乙個一元多項式各項的次數和係數,請按照如下規定的格式要求輸出該多項式 1.多項式中自變數為 x,從左到右按照次數遞減順序給出多項式。2.多項式中只包含係數不為 0 的項。3.如果多項式 n 次項係數...