首页 > 代码库 > BZOJ1089: [SCOI2003]严格n元树

BZOJ1089: [SCOI2003]严格n元树

1089: [SCOI2003]严格n元树

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 762  Solved: 387
[Submit][Status]

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

【样例输入1】
2 2

【样例输入2】
2 3

【样例输入3】
3 5

Sample Output

【样例输出1】
3

【样例输出2】
21

【样例输出2】
58871587162270592645034001

HINT

Source

题解:

先说一下此题我的想法(尽管没有A掉。。。)

考虑递推解此题:

设f[i]表示深度为i的严格n元树的数目,g[i]表示深度为(1--i)的严格n元树的数目。

则我们有如下递推式:

1.f[i]=g[i-1]^n-g[i-2]^n

2.g[i]=g[i-1]+f[i]

第二个是显然的,我们来说一下第一个是怎么来的。

因为我们从i-1递推到i,所以考率在n棵子树上加一个根节点,其余为原先的子树

因为要保证这棵树的深度达到n,所以至少有一个子树的深度达到n-1,

所以每个子树可以有g[i-1]种形态,n棵就是g[i-1]^n,然后去掉不合法的,

不合法的就是每个子树的深度都在1--i-2,即有g[i-2]种选择,也就是 g[i-2]^n

然后如果我们使用累加法的话可以发现 g[i]=g[i-1]^n+1,貌似很简单了?

TLE!!!尽管没有试,但我想是这样的,因为这个复杂度的话,ans必须<=4000位,看起来貌似不可能那么少。。。

高精度乘高精度太浪费时间了,我暂时没有想到好的解决办法。

贴一下上面的代码(没有用累加法)

  1 #include<cstdio>  2   3 #include<cstdlib>  4   5 #include<cmath>  6   7 #include<cstring>  8   9 #include<algorithm> 10  11 #include<iostream> 12  13 #include<vector> 14  15 #include<map> 16  17 #include<set> 18  19 #include<queue> 20  21 #include<string> 22  23 #define inf 1000000000 24  25 #define maxn 50 26  27 #define maxm 500000 28  29 #define eps 1e-10 30  31 #define ll long long 32  33 #define pa pair<int,int> 34  35 #define for0(i,n) for(int i=0;i<=(n);i++) 36  37 #define for1(i,n) for(int i=1;i<=(n);i++) 38  39 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 40  41 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 42  43 #define mod 10000 44  45 using namespace std; 46  47 inline int read() 48  49 { 50  51     int x=0,f=1;char ch=getchar(); 52  53     while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();} 54  55     while(ch>=0&&ch<=9){x=10*x+ch-0;ch=getchar();} 56  57     return x*f; 58  59 } 60 int n,m,f[maxn][maxm],g[2][maxm],t[maxm],c[maxm]; 61 inline void writeln(int *a) 62 { 63     cout<<a[a[0]]; 64     for3(i,a[0]-1,1)cout<<a[i];cout<<endl; 65 } 66 inline void update(int *a) 67 { 68     for1(i,a[0]) 69     { 70         a[i+1]+=a[i]/mod; 71         a[i]%=mod; 72         if(a[a[0]+1])a[0]++; 73     } 74 } 75 inline void mul(int *a,int x) 76 { 77     for1(i,a[0])a[i]*=x; 78     update(a); 79 } 80 inline void jia(int *a,int *b) 81 { 82     a[0]=max(a[0],b[0]); 83     for1(i,a[0]) 84      { 85          a[i]+=b[i]; 86          a[i+1]+=a[i]/mod; 87          a[i]%=mod; 88      } 89     while(!a[a[0]])a[0]--;  90 } 91 inline void cheng(int *a,int *b) 92 { 93     memset(c,0,sizeof(c)); 94     for1(i,a[0]) 95      for1(j,b[0]) 96       { 97        c[i+j-1]+=a[i]*b[j]; 98        c[i+j]+=c[i+j-1]/mod; 99        c[i+j-1]%=mod;100       }101     c[0]=a[0]+b[0]+1;  102     while(!c[c[0]]&&c[0])c[0]--;103     memcpy(a,c,sizeof(c));    104 }105 inline void jian(int *a,int *b)106 {107     for1(i,a[0])108      {109        a[i]-=b[i];110        if(a[i]<0)a[i]+=mod,a[i+1]-=1;111      }112     while(!a[a[0]])a[0]--; 113 }114 115 int main()116 117 {118 119     freopen("input.txt","r",stdin);120 121     freopen("output.txt","w",stdout);122 123     n=read();m=read();124     f[1][f[1][0]=1]=1;125     g[0][g[0][0]=1]=1;126     g[1][g[1][0]=1]=2;127     for2(i,2,m)128     {129         f[i][f[i][0]=1]=1;130         for1(j,n)cheng(f[i],g[1]);131         t[t[0]=1]=1;132         for1(j,n)cheng(t,g[0]);133         jian(f[i],t);134         jia(g[0],f[i-1]);135         jia(g[1],f[i]);136     }137     printf("%d",f[m][f[m][0]]);138     for3(i,f[m][0]-1,1)printf("%04d",f[m][i]);139 140     return 0;141 142 }
View Code

 

 

BZOJ1089: [SCOI2003]严格n元树