zoukankan      html  css  js  c++  java
  • Gym

    题目链接传送门

    题解:

      设定dp[i][j]在深度为i下,使用j个节点的方案数

      显然的转移方程组就是 dp[h][n] = dp[h-1][i] * dp[h-1][n-i-1] + 2*dp[h-1][i]*dp[h-2][n-i-1];

      卷积形式

      利用FFT加速求解dp[h]

    下面是AC代码

    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define ls i<<1
    #define rs ls | 1
    #define mid ((ll+rr)>>1)
    #define pii pair<int,int>
    #define MP make_pair
    typedef long long LL;
    typedef unsigned long long ULL;
    const long long INF = 1e18+1LL;
    const double pi = acos(-1.0);
    const int N = 7e5+10, M = 1e3+20,inf = 2e9;
    
    const long long P=786433LL,mod = 786433LL;
    const LL G=10LL;
    
    LL mul(LL x,LL y){
        return (x*y-(LL)(x/(long double)P*y+1e-3)*P+P)%P;
    }
    LL qpow(LL x,LL k){
        LL ret=1;
        while(k){
            if(k&1) ret=mul(ret,x);
            k>>=1;
            x=mul(x,x);
        }
        return ret;
    }
    LL wn[50];
    void getwn(){
        for(int i=1; i<=40; ++i){
            int t=1<<i;
            wn[i]=qpow(G,(P-1)/t);
        }
    }
    
    int len;
    void NTT(LL y[],int op){
        for(int i=1,j=len>>1,k; i<len-1; ++i){
            if(i<j) swap(y[i],y[j]);
            k=len>>1;
            while(j>=k){
                j-=k;
                k>>=1;
            }
            if(j<k) j+=k;
        }
        int id=0;
        for(int h=2; h<=len; h<<=1) {
            ++id;
            for(int i=0; i<len; i+=h){
                LL w=1;
                for(int j=i; j<i+(h>>1); ++j){
                    LL u=y[j],t=mul(y[j+h/2],w);
                    y[j]=u+t;
                    if(y[j]>=P) y[j]-=P;
                    y[j+h/2]=u-t+P;
                    if(y[j+h/2]>=P) y[j+h/2]-=P;
                    w=mul(w,wn[id]);
                }
            }
        }
        if(op==-1){
            for(int i=1; i<len/2; ++i) swap(y[i],y[len-i]);
            LL inv=qpow(len,P-2);
            for(int i=0; i<len; ++i) y[i]=mul(y[i],inv);
        }
    }
    LL dp[20][N],tmp[N];
    int n,h;
    int main() {
        freopen("avl.in", "r", stdin);
        freopen("avl.out", "w", stdout);
        getwn();
        scanf("%d%d",&n,&h);
        dp[0][1] = 1,dp[1][2] = 2,dp[1][3] = 1;
        len = 1;
        for(int i = 2; i <= h; ++i) {
            len = (1<<(i+1));
            NTT(dp[i-2],1);NTT(dp[i-1],1);
            for(int j = 0; j < len; ++j)
                tmp[j] = (dp[i-1][j] * dp[i-2][j])%mod;
            NTT(tmp,-1);
            for(int j = 1; j < len; ++j)
                dp[i][j] = 2LL*tmp[j-1] % mod;
             for(int j = 0; j < len; ++j)
                tmp[j] = (dp[i-1][j] * dp[i-1][j])%mod;
             NTT(tmp,-1);
             for(int j = 1; j < len; ++j)
                dp[i][j] += tmp[j-1], dp[i][j] %= mod;
            NTT(dp[i-2],-1);
            NTT(dp[i-1],-1);
        }
        printf("%lld
    ",dp[h][n]);
        return 0;
    }
  • 相关阅读:
    小程序 视频
    b161: NOIP2007 4.Hanoi双塔问题
    命名规则、.gitignore、freopen()
    c++学习记录(九)
    c++学习笔记(八)
    2020面向对象程序设计寒假作业2
    c++学习记录(七)
    c++学习记录(六)
    c+学习记录(五)
    c++学习记录(四)
  • 原文地址:https://www.cnblogs.com/zxhl/p/7276836.html
Copyright © 2011-2022 走看看