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

来源:互联网 发布:ubuntu 16.04默认字体 编辑:程序博客网 时间:2024/05/15 04:11

点击这里查看原题

DP,gi表示高度小于i的树的个数,gi=i1j=0f(j)
fi表示高度为i的树的个数。
于是可得

fi=j=1n(nj)fji1gnji1

此题需要用到高精度

#include<bits/stdc++.h>using namespace std;int n,d;struct bignum{    int len,a[1000];    bignum(){        len=0;        memset(a,0,sizeof(a));    }    void modify(){        int i=1,x=0;        for(;x||i<=len;i++){            x+=a[i];            a[i]=x%10000;            x/=10000;        }        len=max(len,i-1);        while(len>1&&!a[len]) len--;    }}f[33][33],g[33][33],c[33][33];bignum operator+(const bignum a,const bignum b){    bignum c;    c.len=max(a.len,b.len);    for(int i=1;i<=c.len;i++){        c.a[i]=a.a[i]+b.a[i];    }    c.modify();    while(c.a[c.len+1]) c.len++;    return c;}bignum operator*(const bignum a,const bignum b){    bignum c;    c.len=a.len+b.len-1;    for(int i=1;i<=a.len;i++){        for(int j=1;j<=b.len;j++){            c.a[i+j-1]+=a.a[i]*b.a[j];        }    }    c.modify();    return c;}bignum itob(int x){    bignum c;    c.len=0;    while(x){        c.a[++c.len]=x%10000;        x/=10000;    }    if(c.len<1) c.len=1;    return c;}void write(bignum &p){    printf("%d",p.a[p.len]);    for(int i=p.len-1;i;i--) printf("%04d",p.a[i]);}int main(){    scanf("%d%d",&n,&d);    for(int i=0;i<=n;i++) c[i][0]=itob(1);    for(int i=1;i<=n;i++){        for(int j=1;j<=i;j++) c[i][j]=c[i-1][j]+c[i-1][j-1];    }    g[0][0]=f[0][0]=itob(1);    for(int i=1;i<=n;i++) f[0][i]=g[0][0];    for(int i=1;i<=d;i++){        f[i][0]=g[i][0]=itob(1);        g[i][1]=g[i-1][1]+f[i-1][1];        for(int j=1;j<=n;j++)            f[i][1]=f[i][1]+c[n][j]*f[i-1][j]*g[i-1][n-j];        for(int j=2;j<=n;j++) f[i][j]=f[i][j-1]*f[i][1],g[i][j]=g[i][j-1]*g[i][1];    }    write(f[d][1]);    printf("\n");    return 0;}