luoguP5383 普通多项式转下降幂多项式 题解

学习了 bztMinamoto 大佬的做法,希望这篇题解可以使得那个方法更加易于理解。

既然下降幂多项式转普通多项式可以采取分治 \(\operatorname{NTT}\),那么可以猜测逆过来也可以。(分治除法???)

引理:考虑,\(\forall j>i\),都有 \(x^{\underline{j}}\bmod x^{\underline{i}}=0\),那么,如果我们只是求 \(x^{\underline{i}}\) 项的系数,我们可以直接把原式模 \(x^{\underline{i+1}}\),再除以 \(x^{\underline{i}}\) 获得答案。(以下除法均为带余除法,如果没有写明取余数,均只取商)。

如果对于每个位置都做两次除法,会导致大量重复计算,所以可以考虑分治做。

具体做法:

我们记 \(D_{l,r}\),表示:

\[D_{l,r}=\prod_{i=l}^{r-1}(x-i) \]

我们通过分治 \(\operatorname{NTT}\) 处理出 \(D_{l,r}\),于是 \(x^{\underline{i}}\),也就是 \(D_{0,i}\) 可以通过 \(O(\log n)\) 个区间合并出来。

不过当然不必如此繁琐,假设我们正在处理 \([l,r)\) 这段区间中下降幂多项式的系数,且已经得到:

\[F'(x)=\frac{F(x)\bmod x^{\underline{r}}}{x^{\underline{l}}} \]

那么,我们将 \(F'(x)\) 除以 \(D_{l,mid}\),将余数放入左子区间,商放入右子区间递归处理即可。

时间复杂度 \(\mathcal O(n\log^{2}n)\)

关键代码:

using namespace Poly_NTT;

const int N = 1 << 18;
int n;
poly F[N << 2], D[N << 2], ans;
#define lc (k << 1)
#define rc ((k << 1) | 1) 
void calc(int k, int l, int r) {//代码中均为闭区间
	if (l == r) {
		D[k] = poly(vector <ll> {(mo - l) % mo, 1});
		return;
	}
	int mid = (l + r) >> 1;
	calc(lc, l, mid);
	calc(rc, mid + 1, r);
	D[k] = D[lc] * D[rc];
}
pair <poly, poly> tmp;
void solve(int k, int l, int r) {
	if (l == r) {
		ans[l] = F[k][0];
		return;
	}
	int mid = (l + r) >> 1;
	tmp = F[k] / D[lc];//second为余数,first为商。
	F[lc] = tmp.second;
	F[rc] = tmp.first;
	solve(lc, l, mid);
	solve(rc, mid + 1, r); 
}
int main() {
	read(n);
	F[1].resize(n); ans.resize(n);
	for (int i = 0; i < n; ++i) {
		read(F[1][i]);
	}
	calc(1, 0, n - 1);
	solve(1, 0, n - 1);
	ans.print();
	return 0;
}

相信大家都有自己的板子了,完整的就不放了,运算符还是很好理解的吧。

posted @ 2022-12-24 08:54  lazytag  阅读(49)  评论(0)    收藏  举报