[BZOJ]1089: [SCOI2003]严格n元树 DP+高精度

Description

  如果一棵树的所有非叶节点都恰好有n个儿子,那么我们称它为严格n元树。如果该树中最底层的节点深度为d(根的深度为0),那么我们称它为一棵深度为d的严格n元树。给出n, d,编程数出深度为d的n元树数目。

Input

  仅包含两个整数n, d( 0 < n < = 32, 0 < = d < = 16)

Output

  仅包含一个数,即深度为d的n元树的数目。

题解:

f[i] 表示深度小于等于 i n元树有多少。可以发现,对于一个 n 元树,都是由根节点+n个子树组成的,而每个子树又是一个深度小于等于 i1 n 元树,再加上一种只有一个根节点的情况,所以有转移方程f[i]=f[i1]n+1。需要用高精度,发博客主要为了存一存新的高精度模版。(以前都是不用重载运算符的)。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=10000;
struct node
{
    int v[10010],l;
}f[20];
node operator * (node a,node b)
{
    node c;
    c.l=a.l+b.l;
    for(int i=1;i<=c.l;i++)c.v[i]=0;
    for(int i=1;i<=a.l;i++)
    for(int j=1;j<=b.l;j++)
    c.v[i+j-1]+=a.v[i]*b.v[j];
    for(int i=1;i<=c.l;i++)
    if(c.v[i]>=M)
    {
        if(i==c.l)c.v[++c.l]=c.v[i]/M;
        else c.v[i+1]+=c.v[i]/M;
        c.v[i]%=M;
    }
    while(c.l>1&&!c.v[c.l])c.l--;
    return c;
}
node operator + (node a,int b)
{
    node c=a;
    c.v[1]+=b;
    for(int i=1;i<=c.l;i++)
    if(c.v[i]>=M)
    {
        if(i==c.l)c.v[++c.l]=c.v[i]/M;
        else c.v[i+1]+=c.v[i]/M;
        c.v[i]%=M;
    }
    return c;
}
node operator - (node a,node b)
{
    node c;
    c.l=max(a.l,b.l);
    for(int i=1;i<=c.l;i++)c.v[i]=0;
    for(int i=1;i<=c.l;i++)
    {
        c.v[i]+=a.v[i]-b.v[i];
        if(c.v[i]<0)
        {
            c.v[i]+=M;
            c.v[i+1]--;
            if(i+1==c.l&&c.v[i+1]==0)c.l--;
        }
    }
    while(c.l>1&&!c.v[c.l])c.l--;
    return c;
}
node p(node x,int y)
{
    if(y==1)return x;
    node t=p(x,y>>1),ans=t*t;
    if(y&1)ans=ans*x;
    return ans;
}
int main()
{
    int n,d;
    scanf("%d%d",&n,&d);
    if(d==0){puts("1");return 0;}
    f[0].v[1]=1;f[0].l=1;
    for(int i=1;i<=d;i++)f[i]=p(f[i-1],n)+1;
    node ans=f[d]-f[d-1];
    printf("%d",ans.v[ans.l]);
    for(int i=ans.l-1;i;i--)
    printf("%04d",ans.v[i]);
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值