Andrew Stankevich Contest 46 Problem D. Dichromatic Trees
阿新 • • 發佈:2021-08-23
MTT加速DP
\[\rm G[i][j]=\sum\limits_{k=0}^{i-1}(F[k][j-1]+G[k][j-1])*(F[i-k][j-1]+G[i-k][j-1])
\]
題意:定義紅黑樹如下:只有紅點和黑點的二叉樹,紅點的兒子必須為黑點;從根出發到任意一個不足兩個兒子的點,經過的黑點個數定義為black height。問n個點,black height小於等於H的紅黑樹種類數,答案對258280327取模
設F[i][j]表示根節點為紅色,包含i個節點,black height為j的紅黑樹個數
G[i][j]表示根節點為黑色,包含i個節點,black height為j的紅黑樹個數
考慮到紅色節點的兒子只能為黑色,且紅點不改變black height,那麼有
同時,黑點的兒子沒有限制,紅黑均可,且會對black height貢獻1,那麼有
可以發現,F和G的轉移類似於卷積的形式,且模數找不到原根,用MTT加速轉移H次即可
#include <bits/stdc++.h> #define int long long using namespace std; #define rep(i,x,y) for(int i=x;i<=y;i++) int rd() { int ret = 0, f = 1;char c; while (c = getchar(), !isdigit(c))f = c == '-' ? -1 : 1; while (isdigit(c))ret = ret * 10 + c - '0', c = getchar(); return ret * f; } typedef long long ll; typedef long double ld; const int inf = 1 << 30; const int MAXN = 524289+2; int MOD = 258280327; const int BASE = 1 << 15; const ld Pi = acos(-1.0); struct CP { ld x, y; CP(ld xx = 0, ld yy = 0) { x = xx; y = yy; } } P1[MAXN << 2], P2[MAXN << 2], Q[MAXN << 2]; CP operator+(CP a, CP b) { return {a.x + b.x, a.y + b.y}; } CP operator-(CP a, CP b) { return {a.x - b.x, a.y - b.y}; } CP operator*(CP a, CP b) { return {a.x *b.x - a.y * b.y, a.x *b.y + a.y * b.x}; } int limit, r[MAXN << 2]; ll qpow(ll x, ll y) { ll ret = 1, base = x; while (y) { if (y & 1) ret = ret * base % MOD; base = base * base % MOD; y >>= 1; } return ret; } void FFT(CP *A, int type) { for (int i = 0; i < limit; i++) if (i < r[i]) swap(A[i], A[r[i]]); for (int mid = 1; mid < limit; mid <<= 1) { CP Wn(cos(Pi / mid), type * sin(Pi / mid)); for (int R = mid << 1, j = 0; j < limit; j += R) { CP w(1, 0); for (int k = 0; k < mid; k++, w = w * Wn) { CP x = A[j + k], y = w * A[j + mid + k]; A[j + k] = x + y; A[j + mid + k] = x - y; } } } } void init(int n) { limit = 1; while (limit <= n) limit <<= 1; for (int i = 1; i < limit; i++) r[i] = r[i >> 1] >> 1 | ((i & 1) ? limit >> 1 : 0); } int MTT(int *a, int *b, int n, int m, int *res, int MOD) { // init(n + m); for (int i = 0; i < n; i++) { P1[i] = {a[i] / BASE, a[i] % BASE}; P2[i] = {a[i] / BASE, -a[i] % BASE}; } for (int i = n; i < limit; i++) P1[i] = P2[i] = {0, 0}; for (int i = 0; i < m; i++) Q[i] = {b[i] / BASE, b[i] % BASE}; for (int i = m; i < limit; i++) Q[i] = {0, 0}; FFT(P1, 1); FFT(P2, 1); FFT(Q, 1); for (int i = 0; i < limit; i++) { Q[i].x /= limit, Q[i].y /= limit; P1[i] = P1[i] * Q[i], P2[i] = P2[i] * Q[i]; } FFT(P1, -1); FFT(P2, -1); for (int i = 0; i < n + m - 1; i++) { ll a1b1, a1b2, a2b1, a2b2; a1b1 = (ll)floor((P1[i].x + P2[i].x) / 2 + 0.5) % MOD; a1b2 = (ll)floor((P1[i].y + P2[i].y) / 2 + 0.5) % MOD; a2b1 = (ll)floor((P1[i].y - P2[i].y) / 2 + 0.5) % MOD; a2b2 = (ll)floor((P2[i].x - P1[i].x) / 2 + 0.5) % MOD; res[i] = ((a1b1 * BASE + (a1b2 + a2b1)) * BASE + a2b2) % MOD; res[i] = (res[i] + MOD) % MOD; } return n + m - 1; } int B[MAXN * 8], tot; struct Poly { int *a, len; void init0(int _len) { len = _len; a = B + tot; for (int i = 0; i < len; i++) a[i] = 0; tot += len; } void init(int _len, int *src) { len = _len; a = B + tot; for (int i = 0; i < len; i++) a[i] = src[i]; tot += len; } void mul(const Poly &rhs) { len = MTT(a, rhs.a, len, rhs.len, a, MOD); } }; const int LEN = 131072+2; signed main() { freopen("dichromatic.in","r",stdin); freopen("dichromatic.out","w",stdout); int n, hh; cin>>n>>hh; static int F[MAXN], G[MAXN], H[MAXN],tmp[MAXN]; static int ans[MAXN]; init(LEN+LEN); F[0]=1; F[1]=1; for (int t = 1; t <= hh ; t++) { for (int i = 0; i <= LEN; i++) { H[i] = (F[i] + G[i]) % MOD; ans[i] = (ans[i] + H[i]) % MOD; } MTT(H, H, LEN, LEN, tmp, MOD); rep(i,1,LEN) G[i]=tmp[i-1]; MTT(G, G, LEN, LEN, tmp, MOD); rep(i,1,LEN) F[i]=tmp[i-1]; F[0]=G[0]=0; } for (int i = 0; i <= LEN; i++) { H[i] = (F[i] + G[i]) % MOD; ans[i] = (ans[i] + H[i]) % MOD; } for(int i=1;i<=n;i++){ int xx; cin>>xx; cout<<ans[xx]<<" "; } }
本文來自部落格園,作者:GhostCai,轉載請註明原文連結:https://www.cnblogs.com/ghostcai/p/15177413.html