zoukankan      html  css  js  c++  java
  • Petrozavodsk Winter Camp, Andrew, 2014, 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 << '
    ';
        int k, H, n;
        scanf("%d%d", &k, &H);
        rep(i, 1, k) {
            scanf("%d", &n);
            cout << (red[H][n] + black[H][n]) % MOD << '
    ';
        }
    }
  • 相关阅读:
    P2437 蜜蜂路线题解
    P1044 栈题解
    P1002 过河卒题解
    P1433 吃奶酪题解
    组合数公式
    P1036 选数题解
    十进制转二进制方法整理
    golang学习笔记 ---工作区与GOPATH
    golang学习笔记---闭包
    golang学习笔记---类型
  • 原文地址:https://www.cnblogs.com/tempestT/p/10658260.html
Copyright © 2011-2022 走看看