Dichromatic Trees

条件:

1:每个红色节点的儿子都是黑色节点

2.每个叶子到根路径上的黑点数相等,等于某个常数,称作树的black height

求给定black height和节点数的符合条件的方案数

$black_{h} = x (black_{h-1} + red_{h-1})^2$

$red_{h} = x black_{h}^2$

任意模数的fft

#include <bits/stdc++.h>
using namespace std;
#define rep(i, j, k) for (int i = int(j); i <= int(k); ++ i) 
#define dwn(i, j, k) for (int i = int(j); i >= int(k); -- i)
typedef long long LL;
const int MOD = 258280327;
const int N = 1 << 18;
const long double PI = acos(-1.);
LL red[17][N], black[17][N], M = 32767;
struct Complex {
    long double r, i;
    Complex(long double _r = 0, long double _i = 0) {
        r = _r; i = _i;
    }    
    Complex operator + (const Complex &rhs) const {
        return Complex(r + rhs.r, i + rhs.i);
    }
    Complex operator - (const Complex &rhs) const {
        return Complex(r - rhs.r, i - rhs.i);
    }
    Complex operator * (const Complex &rhs) const {
        return Complex(r * rhs.r - i * rhs.i, r * rhs.i + i * rhs.r);
    }
    Complex operator / (long double b) const {
        return Complex(r / b, i / b);
    }
};
int a[N], b[N], c[N];
Complex conj(Complex &a) {
    return Complex(a.r, -a.i);
}
void fft(Complex *a, int n, int t) {
    int k = 0; 
    while ((1 << k) < n) k ++;
    rep(i, 0, n - 1) {
        int t = 0;
        rep(j, 0, k - 1) if ((i >> j) & 1) t |= (1 << (k - 1 - j));
        if (i < t) swap(a[i], a[t]);
    }

    for (int l = 2; l <= n; l <<= 1) {
        int m = l >> 1; 
        long double o = 2 * PI / l * t; Complex _w(cos(o), sin(o));
        for (int i = 0; i < n; i += l) {
            Complex w(1, 0);
            rep(j, 0, m - 1) {
                Complex x = w * a[i + j + m];
                a[i + j + m] = a[i + j] - x;
                a[i + j] = a[i + j] + x;
                w = w * _w;
            }
        }
    }
    if (t == -1) rep(i, 0, n - 1) a[i] = a[i] / n;
}
void Mul(int *A, int *B, int *C, int len, LL P) {
    for(int i = 0;i < len; ++i) (A[i] += P) %= P, (B[i] += P) %= P;
    static Complex a[N], b[N], Da[N], Db[N], Dc[N], Dd[N];
    for(int i = 0;i < len; ++i) a[i] = Complex(A[i] & M, A[i] >> 15);
    for(int i = 0;i < len; ++i) b[i] = Complex(B[i] & M, B[i] >> 15);
    fft(a, len, 1); fft(b, len, 1);
    for(int i = 0;i < len; ++i) {
        int j = (len - i) & (len - 1); static Complex da, db, dc, dd;
        da = (a[i] + conj(a[j])) * Complex(0.5, 0);
        db = (a[i] - conj(a[j])) * Complex(0, -0.5);
        dc = (b[i] + conj(b[j])) * Complex(0.5, 0);
        dd = (b[i] - conj(b[j])) * Complex(0, -0.5);
        Da[j] = da * dc; Db[j] = da * dd; Dc[j] = db * dc; Dd[j] = db * dd; //顺便区间反转,方便等会直接用DFT代替IDFT 
    }
    for(int i = 0;i < len; ++i) a[i] = Da[i] + Db[i] * Complex(0, 1);
    for(int i = 0;i < len; ++i) b[i] = Dc[i] + Dd[i] * Complex(0, 1);
    fft(a, len, 1); fft(b, len, 1);
    for(int i = 0;i < len; ++i) {
        int da = (LL) (a[i].r / len + 0.5) % P; //直接取实部和虚部 
        int db = (LL) (a[i].i / len + 0.5) % P;
        int dc = (LL) (b[i].r / len + 0.5) % P;
        int dd = (LL) (b[i].i / len + 0.5) % P;
        C[i] = (da + ((LL)(db + dc) << 15) + ((LL)dd << 30)) % P; 
    }
}

int main() {
    red[0][1] = 1; red[0][0] = 1;
    int len1 = 1 << 17, len2 = 1 << 18;
    
    rep(h, 1, 16) {
        rep(i, 0, len1 - 1) a[i] = (black[h - 1][i] + red[h - 1][i]) % MOD, b[i] = a[i];
        rep(i, len1, len2 - 1) a[i] = b[i] = 0;
        Mul(a, b, c, len2, MOD);
        rep(i, 1, len1) black[h][i] = c[i - 1];
        rep(i, 0, len1 - 1) a[i] = black[h][i], b[i] = a[i];
        rep(i, len1, len2 - 1) a[i] = b[i] = 0;
        Mul(a, b, c, len2, MOD);
        rep(i, 1, len1) red[h][i] = c[i - 1];
     }

    rep(i, 1, len1) rep(j, 1, 16) {
        (red[j][i] += red[j - 1][i]) %= MOD;
        (black[j][i] += black[j - 1][i]) %= MOD;
    }
    // rep(i, 0, 10) cout <<  black[1][i] << ' '; cout << '\n';
    int k, H, n;
    scanf("%d%d", &k, &H);
    rep(i, 1, k) {
        scanf("%d", &n);
        cout << (red[H][n] + black[H][n]) % MOD << '\n';
    }
}

猜你喜欢

转载自www.cnblogs.com/tempestT/p/10658260.html
今日推荐