学习了 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;
}
相信大家都有自己的板子了,完整的就不放了,运算符还是很好理解的吧。
标签:tmp,lc,int,多项式,mid,题解,luoguP5383,underline From: https://www.cnblogs.com/lazytag/p/17001987.html