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

 感觉不会再爱了,这居然就是正解QAQ

不会貌似别人解释的更简单,直接推g[i]的表达式也很简单。

妈蛋,数据范围给的太大了,和lydsy要过来数据发现全是非常小的T_T

我做了2天多,一直在对拍自己的程序为什么出错,AC的程序运行过程中答案为什么会越来越小,我的程序为什么10 15的点都跑不出来,而且位数剧增

今天才发现是别人的空间爆了啊。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

还以为是我的程序错了啊。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

看来我的推断没有错,如果数据范围真如题中所说,那么答案的位数就太大了。

我要去建议lydsy修改此题的题面,不要再像坑我一样坑了其他人。。。

 代码:

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

不过还是有几点收获的:

1.捞到一个高精度模版

2.class里数组要开小

posted @ 2014-09-18 18:44  ZYF-ZYF  Views(253)  Comments(0Edit  收藏  举报