BZOJ1089——[SCOI2003]严格n元树

1、题意:求深度为d的n叉树的个数。

2、分析:动态规划。。设Fi表示深度小于等于i的n叉树有多少,然后可以考虑dp,新加入一个点,设这个点为根,那么这个点的每个儿子都有Fi种方案,所以是Fni,加上这个点自己本身也是一个n叉树,所以Fi=Fni+1,这就是转移方程,别忘了高精度= =

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;

inline int read(){
    char ch = getchar(); int x = 0, f = 1;
    while(ch < ‘0‘ || ch > ‘9‘){
        if(ch == ‘-‘) f = -1;
        ch = getchar();
    }
    while(‘0‘ <= ch && ch <= ‘9‘){
        x = x * 10 + ch - ‘0‘;
        ch = getchar();
    }
    return x * f;
}

struct bign{
    int a[210];
    int len;

    bign(){
        memset(a, 0, sizeof(a));
        len = 0;
    }

    inline bign get_bign(int rhs){
        bign ret;
        while(rhs){
            ret.a[++ ret.len] = rhs % 10;
            rhs /= 10;
        }
        return ret;
    }

    inline bool operator < (const bign& rhs) const{
        if(len < rhs.len) return 1;
        if(len > rhs.len) return 0;
        for(int i = len; i >= 1; i --){
            if(a[i] < rhs.a[i]) return 1;
            if(a[i] > rhs.a[i]) return 0;
        }
        return 0;
    }

    inline bool operator > (const bign& rhs) const{
        return rhs < *this;
    }

    inline bool operator == (const bign& rhs) const{
        return !((rhs < *this) | (*this < rhs));
    }

    inline bool operator <= (const bign& rhs) const{
        return *this == rhs || *this < rhs;
    }

    inline bool operator >= (const bign& rhs) const{
        return *this == rhs || *this > rhs;
    }

    inline bool operator != (const bign& rhs) const{
        return !(*this == rhs);
    }

    inline bign operator * (bign& rhs) const{
        bign ret;
        for(int i = 1; i <= len; i ++){
            for(int j = 1; j <= rhs.len; j ++){
                ret.a[i + j - 1] += a[i] * rhs.a[j];
                ret.a[i + j] += ret.a[i + j - 1] / 10;
                ret.a[i + j - 1] %= 10;
            }
        }
        ret.len = len + rhs.len - 1;
        if(ret.a[ret.len + 1]) ret.len ++;
    /*  puts("");
        for(int i = len; i >= 1; i --) printf("%d", a[i]);
        puts("");
        puts("*");
        rhs.print();
        puts("=");
        ret.print();
        puts("");*/
        return ret;
    }

    inline bign operator * (int& rhs){
        bign yt = get_bign(rhs);
        return *this * yt;
    } 

    inline bign operator + (bign& rhs) const{
        bign ret;
        ret.len = max(len, rhs.len);
        for(int i = 1; i <= ret.len; i ++){
            ret.a[i] += a[i] + rhs.a[i];
            ret.a[i + 1] += ret.a[i] / 10;
            ret.a[i] %= 10;
        }
        if(ret.a[ret.len + 1]) ret.len ++;
        return ret;
    }

    inline bign operator + (int& rhs){
        bign yt = get_bign(rhs);
        return *this + yt;
    }

    inline bign operator - (const bign& rhs) const{
        bign ret;
        for(int i = 1; i <= len; i ++){
            ret.a[i] += a[i] - rhs.a[i];
            if(ret.a[i] < 0) ret.a[i] += 10, ret.a[i + 1] --;
            if(ret.a[i]) ret.len = i;
        }
        return ret;
    }

    inline bign operator - (int& rhs){
        bign yt = get_bign(rhs);
        return *this - yt;
    }  

    inline bign operator / (const int& rhs) const{
        bign ret;
        int x = 0;
        for(int i = len; i >= 1; i --){
            x = x * 10 + a[i];
            ret.a[i] = x / rhs;
            x %= rhs;
        }
        ret.len = len;
        while(!ret.a[ret.len] && ret.len) ret.len --;
        return ret;
    }

    inline int operator % (const int& rhs) const{
        int x = 0;
        for(int i = len; i >= 1; i --){
            x = x * 10 + a[i];
            x %= rhs;
        }
        return x;
    } 

    inline bign operator ^ (int rhs){
        bign ret; ret = get_bign(1);
        bign nbc = *this;
        //puts("fuck");
        //nbc.print();
        while(rhs){
            if(rhs & 1) ret = ret * nbc;
            nbc = nbc * nbc;
            rhs >>= 1;
        }
        //ret.print();
        return ret;
    }

    inline void operator = (int x){
        *this = get_bign(x);
        return;
    } 

    inline void print(){
        for(int i = len; i >= 1; i --) printf("%d", a[i]);
        //puts("");
    }
} F[20]; 

int main(){
    //freopen("0input.in", "r", stdin);
    int n = read(), d = read();
    if(d == 0){
        puts("1");
        return 0;
    }
    F[0] = 1;// F[0].print();
    for(int i = 1; i <= d; i ++){
        F[i] = F[i - 1] ^ n; //printf("^");F[i].print();
        F[i] = F[i] + F[0]; //F[i].print();
        //printf("N:%d\n", n);
    }
    (F[d] - F[d - 1]).print();
    return 0;
} 
时间: 2024-10-13 12:07:08

BZOJ1089——[SCOI2003]严格n元树的相关文章

[BZOJ1089][SCOI2003]严格n元树(递推+高精度)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1089 分析: 第一感觉可以用一个通式求出来,但是考虑一下很麻烦,不好搞的.很容易发现最底层必有一个是满高度的,其他的任意. 所以直接的递推也不好想. (以下所述都是n元树) 于是可以令f[d]为深度<=d的树的个数,那么深度为d的就是f[d]-f[d-1] 对于深度<=d的又该怎么处理呢? 考虑第一层的n个点(根为0层),每个点都要底下连子树,深度为0~i-1,方案数即f[d-1]

BZOJ1089 [SCOI2003]严格n元树

又是一道奇怪的DP(?)题一个非常好的想法是:令f[i]表示深度小于等于i的n元树的总个数,于是f[i] = f[i - 1] ^ n + 1 (这是因为加了一层以后新的根的n个儿子可以随便选,再加上没有儿子的情况)但是还要写高精...还好一边A了,手感不错~ 1 /************************************************************** 2 Problem: 1089 3 User: rausen 4 Language: Pascal 5 R

bzoj 1089 [SCOI2003]严格n元树(DP+高精度)

1089: [SCOI2003]严格n元树 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1250  Solved: 621[Submit][Status][Discuss] Description 如果一棵树的所有非叶节点都恰好有n个儿子,那么我们称它为严格n元树.如果该树中最底层的节点深度为d(根的深度为0),那么我们称它为一棵深度为d的严格n元树.例如,深度为2的严格2元树有三个,如下图: 给出n, d,编程数出深度为d的n元树数目. Inp

【BZOJ 1089】 [SCOI2003]严格n元树

1089: [SCOI2003]严格n元树 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 872  Solved: 445 [Submit][Status] Description 如果一棵树的所有非叶节点都恰好有n个儿子,那么我们称它为严格n元树.如果该树中最底层的节点深度为d(根的深度为0),那么我们称它为一棵深度为d的严格n元树.例如,深度为2的严格2元树有三个,如下图: 给出n, d,编程数出深度为d的n元树数目. Input 仅包含两个

BZOJ 1089: [SCOI2003]严格n元树

Decription 询问深度为 \(d\) 的 \(n\) 元树个数, \(n\) 元树所有节点的孩子都有 \(n\) 个. Sol 递推+高精度. \(f[i]\) 表示深度为 \(i\) 的 \(n\) 元树个数,我这里深度是从 \([1,k+1]\) 的... 转移就是从上方添加一个节点,子节点任选然后再减去不合法的方案. \(f[i]=(\sum ^{i-1} _{j=1} f[j])^n-(\sum ^{i-2} _{j=1} f[j])^n\) Code #include<cstd

BZOJ 1089 SCOI2003 严格n元树 动态规划+高精度

题目大意:定义一棵深度为d的严格n元树为根的深度为0,最深的节点深度为d,且每一个非叶节点都有恰好n个子节点的树 给定n和d,求深度为d的严格n元树一共同拥有多少种 此题的递推部分并不难 首先我们设深度为i的严格n元树一共同拥有f[i]种 令S[i]为f[i]的前缀和 我们不难发现一棵深度为i下面的严格n元树由两部分组成:一个根节点,n棵子树.当中每棵子树的深度不超过i-1 每棵子树有S[i-1]种 一共n棵子树 于是S[i]=S[i-1]^n 嗯?是不是少了点东西?没错,另一种情况,这棵严格n

【bzoj1089】严格n元树

Description 如果一棵树的所有非叶节点都恰好有n个儿子,那么我们称它为严格n元树.如果该树中最底层的节点深度为d(根的深度为0),那么我们称它为一棵深度为d的严格n元树.例如,深度为2的严格2元树有三个,如下图: 给出n, d,编程数出深度为d的n元树数目. Input 仅包含两个整数n, d( 0   <   n   <   =   32,   0  < =   d  < = 16) Output 仅包含一个数,即深度为d的n元树的数目. Sample Input [样

【BZOJ】1089: [SCOI2003]严格n元树(递推+高精度/fft)

http://www.lydsy.com/JudgeOnline/problem.php?id=1089 想了好久的递推式,,,然后放弃了QAQ 神思路!orz 首先我们设$f[i]$表示深度最大为i的n元树的数目,注意,是最大深度为i! 那么易得递推式 f[i]=f[i-1]^n+1 前面表示子树的情况乘积,后面表示树为1层!因为1层是合法的!即没有子女! 然后答案就是 f[d]-f[d-1] !!!为什么要剪掉呢?因为看我们的转移,并不是深度为i,而是深度最大为i,那么为什么要这样减呢?理由

P4295 [SCOI2003]严格N元树 DP

思路:DP 提交:\(5\)次 错因:\(2\)次高精写错(我太菜了),\(2次\)写错特判 题解: 设\(f[i]\)表示深度\(\leq i\)的严格\(n\)元树的数目,有 \[f[i]=pow(f[i-1],n)+1\] 即一个点,对于每一个孩子深度都可以是\(1\)到\(i-1\)的严格\(n\)元树,或是仅仅一个点(作为根). 所以最后的答案是\(f[i]-f[i-1]\) 需要高精. #include<cstdio> #include<iostream> #inclu