CF 438E The Child and Binary Tree
BZOJ 3625
吐槽
BZOJ上至今没有卡过去,太慢了卡得我不敢交了……
一件很奇怪的事情就是不管是本地还是自己上传数据到OJ测试都远远没有到达时限。
本题做法
设$f_i$表示权值为$i$的二叉树的个数,因为一棵二叉树可以通过左右儿子构建起来转移,我们可以得到转移:
$$f_w = \sum_{x, y, w - (x + y) \in c} f_x * f_y$$
注意到左右子树可以为空,所以$f_0 = 1$。
很容易发现这是一个卷积的形式,我们尝试把它写得好看一点。
先把物品写成生成函数的形式,记
$$G(x) = \sum_{i = 0}^{m}[i \in c]x^i$$
题目保证了$G(0) = 0$。
再用$F(x)$表示权值为$x$的二叉树的个数,有
$$F(n) = \sum_{i = 1}^{n}G(i)\sum_{j = 1}^{n - i}F(j)F(n - i - j)$$
$$F(n) = (G * F ^ 2)(n)$$
发现多项式$F$除了第$0$项每一项都可以由上面这个式子得到,而$F(0) = 1$。
得到
$$F = G * F ^ 2 + 1$$
解一元二次方程,
$$F = \frac{2}{1 \pm \sqrt{1 - 4G}}$$
考虑到$G(0) = 0$,$F(0) = 1$,所以取加号。
剩下就是怎么开根的问题。
多项式开根
假设已经求出了$F_0(x)$使$G(F_0(x)) \equiv 0 (\mod x^{\left \lceil \frac{n}{2} \right \rceil})$成立,要求$F(x)$使$G(F(x)) \equiv 0 (\mod x^n)$成立。
在多项式$exp$那里已经提过了这里$G(F(x)) = F(x)^2 - A(x)$。
牛顿迭代的式子拿出来,
$$F(x) \equiv F_0(x) - \frac{G(F_0(x))}{G'(F_0(x))}( \mod x^n)$$
$$G'(F(x)) = 2F(x)$$
代进去
$$F(x) \equiv \frac{F_0(x)^2 + A(x)}{2F_0(x)}(\mod x^n)$$
可以递归计算了。
$$T(n) = T(\frac{n}{2}) + O(nlogn)$$
时间复杂度还是$O(nlogn)$,常数极大就是了。
Code:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int N = 1 << 18; int n, m, a[N]; ll f[N], g[N]; namespace Poly { const int L = 1 << 18; const ll P = 998244353LL; int lim, pos[L]; ll f[L], g[L], h[L], tmp[L]; inline ll fpow(ll x, ll y) { ll res = 1; for (x %= P; y > 0; y >>= 1) { if (y & 1) res = res * x % P; x = x * x % P; } return res; } const ll inv2 = fpow(2, P - 2); inline void prework(int len) { int l = 0; for (lim = 1; lim < len; lim <<= 1, ++l); for (int i = 0; i < lim; i++) pos[i] = (pos[i >> 1] >> 1) | ((i & 1) << (l - 1)); } inline void ntt(ll *c, int opt) { for (int i = 0; i < lim; i++) if (i < pos[i]) swap(c[i], c[pos[i]]); for (int i = 1; i < lim; i <<= 1) { ll wn = fpow(3, (P - 1) / (i << 1)); if (opt == -1) wn = fpow(wn, P - 2); for (int len = i << 1, j = 0; j < lim; j += len) { ll w = 1; for (int k = 0; k < i; k++, w = w * wn % P) { ll x = c[j + k], y = w * c[j + k + i] % P; c[j + k] = (x + y) % P, c[j + k + i] = (x - y + P) % P; } } } if (opt == -1) { ll inv = fpow(lim, P - 2); for (int i = 0; i < lim; i++) c[i] = c[i] * inv % P; } } void inv(ll *a, ll *b, int len) { if (len == 1) { b[0] = fpow(a[0], P - 2); return; } inv(a, b, (len + 1) >> 1); prework(len << 1); for (int i = 0; i < lim; i++) f[i] = g[i] = 0; for (int i = 0; i < len; i++) f[i] = a[i], g[i] = b[i]; ntt(f, 1), ntt(g, 1); for (int i = 0; i < lim; i++) g[i] = g[i] * (2LL - g[i] * f[i] % P + P) % P; ntt(g, -1); for (int i = 0; i < len; i++) b[i] = g[i]; } inline void direv(ll *c, int len) { for (int i = 0; i < len - 1; i++) c[i] = c[i + 1] * (i + 1) % P; c[len - 1] = 0; } inline void integ(ll *c, int len) { for (int i = len - 1; i > 0; i--) c[i] = c[i - 1] * fpow(i, P - 2) % P; c[0] = 0; } inline void ln(ll *a, ll *b, int len) { for (int i = 0; i < len; i++) h[i] = 0; inv(a, h, len); for (int i = 0; i < len; i++) b[i] = a[i]; direv(b, len); prework(len << 1); ntt(h, 1), ntt(b, 1); for (int i = 0; i < lim; i++) b[i] = b[i] * h[i] % P; ntt(b, -1); integ(b, len); } ll F[L], G[L], H[L]; void exp(ll *a, ll *b, int len) { if (len == 1) { b[0] = 1; return; } exp(a, b, (len + 1) >> 1); ln(b, F, len); F[0] = (a[0] % P + 1 - F[0] + P) % P; for (int i = 1; i < len; i++) F[i] = (a[i] - F[i] + P) % P; prework(len << 1); for (int i = len; i < lim; i++) F[i] = 0; for (int i = 0; i < lim; i++) G[i] = 0; for (int i = 0; i < len; i++) G[i] = b[i]; ntt(F, 1), ntt(G, 1); for (int i = 0; i < lim; i++) F[i] = F[i] * G[i] % P; ntt(F, -1); for (int i = 0; i < len; i++) b[i] = F[i]; } void sqr(ll *a, ll *b, int len) { if (len == 1) { b[0] = a[0]; return; } sqr(a, b, (len + 1) >> 1); for (int i = 0; i < len; i++) H[i] = 0; inv(b, H, len); prework(len << 1); for (int i = 0; i < lim; i++) F[i] = G[i] = 0; for (int i = 0; i < len; i++) F[i] = a[i], G[i] = b[i]; ntt(F, 1), ntt(G, 1), ntt(H, 1); for (int i = 0; i < lim; i++) F[i] = (G[i] * G[i] % P + F[i] + P) % P * inv2 % P * H[i] % P; ntt(F, -1); for (int i = 0; i < len; i++) b[i] = F[i]; } }; using Poly :: fpow; using Poly :: P; /* template <typename T> inline void read(T &X) { X = 0; char ch = 0; T op = 1; for (; ch > '9'|| ch < '0'; ch = getchar()) if (ch == '-') op = -1; for (; ch >= '0' && ch <= '9'; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } */ namespace Fread { const int L = 1 << 15; char buffer[L], *S, *T; inline char Getchar() { if(S == T) { T = (S = buffer) + fread(buffer, 1, L, stdin); if(S == T) return EOF; } return *S++; } template <class T> inline void read(T &X) { char ch; T op = 1; for(ch = Getchar(); ch > '9' || ch < '0'; ch = Getchar()) if(ch == '-') op = -1; for(X = 0; ch >= '0' && ch <= '9'; ch = Getchar()) X = (X << 1) + (X << 3) + ch - '0'; X *= op; } } using namespace Fread; namespace Fwrite { const int L = 2e6 + 5; int bufp = 0; char buf[L]; template <typename T> inline void write(T x) { if(!x) buf[++bufp] = '0'; if(x < 0) { buf[++bufp] = '-'; x = -x; } int st[15], tp = 0; for(; x; x /= 10) st[++tp] = x % 10; for(; tp; tp--) buf[++bufp] = (st[tp] + '0'); buf[++bufp] = '\n'; } } using namespace Fwrite; template <typename T> inline void inc(T &x, T y) { x += y; if (x >= P) x -= P; } template <typename T> inline void sub(T &x, T y) { x -= y; if (x < 0) x += P; } int main() { /* #ifndef ONLINE_JUDGE freopen("Sample.txt", "r", stdin); #endif */ // freopen("3625.in", "r", stdin); // freopen("3625.out", "w", stdout); read(n), read(m); for (int x, i = 1; i <= n; i++) { read(x); if (x <= m) g[x] = 1; } /* for (int i = 0; i <= m; i++) printf("%lld%c", g[i], " \n"[i == m]); */ g[0] = 1; for (int i = 1; i <= m; i++) g[i] = (P - 4LL * g[i] % P) % P; Poly :: sqr(g, f, m + 1); /* for (int i = 0; i <= m; i++) printf("%lld%c", g[i], " \n"[i == m]); for (int i = 0; i <= m; i++) printf("%lld%c", f[i], " \n"[i == m]); */ inc(f[0], 1LL); for (int i = 0; i <= m; i++) g[i] = 0; Poly :: inv(f, g, m + 1); /* for (int i = 0; i <= m; i++) printf("%lld%c", f[i], " \n"[i == m]); */ for (int i = 1; i <= m; i++) { // write(g[i] * 2LL % P); // printf("\n"); printf("%lld\n", (g[i] + g[i]) % P); } // fwrite(buf + 1, 1, bufp, stdout); return 0; }