bzoj1089: [SCOI2003]严格n元树(高精度)

35 篇文章 0 订阅

题目传送门

解法:
好神啊。
f[i]表示深度小于等于i的严格n元树。
那么f[i]怎么用f[i-1]表示呢。
对于任意一个深度为i的严格n元树。
那么它的根一定有n个儿子。
这样我们就可以把它拆成一个根和n棵深度小于等于i-1的n元树了。
那么深度小于等于i-1的n元树方案已经求出来了是f[i-1]了呀。
那么在利用乘法原理得出f[i]=f[i-1]^n。
还没完,还有一棵只有根节点的树,所以f[i]还得+1。

代码实现:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
struct node {int len,a[11000];node() {len=0;memset(a,0,sizeof(a));}}a,b;
node jiafa(node n1) {
    node no=n1;no.a[1]++;
    for(int i=1;i<=no.len;i++) {no.a[i+1]+=no.a[i]/10;no.a[i]%=10;}
    int i=no.len;while(no.a[i+1]>0) {i++;no.a[i+1]+=no.a[i]/10;no.a[i]%=10;}no.len=i;
    return no;
}
node jianfa(node n1,node n2) {
    node no;no.len=n1.len;
    for(int i=1;i<=no.len;i++)no.a[i]=n1.a[i]-n2.a[i];
    for(int i=1;i<=no.len;i++)if(no.a[i]<0){no.a[i]+=10;no.a[i+1]--;}
    int i=no.len;while(no.a[i]==0&&i>1)i--;no.len=i;
    return no;
}
node chengfa(node n1,node n2) {
    node no;no.len=n1.len+n2.len-1;
    for(int i=1;i<=n1.len;i++)for(int j=1;j<=n2.len;j++)no.a[i+j-1]+=n1.a[i]*n2.a[j];
    for(int i=1;i<=no.len;i++) {no.a[i+1]+=no.a[i]/10;no.a[i]%=10;}
    int i=no.len;while(no.a[i+1]>0) {i++;no.a[i+1]+=no.a[i]/10;no.a[i]%=10;}no.len=i;
    return no;
}
node pow(node n1,int b) {
    node ans;ans.len=1;ans.a[1]=1;
    while(b!=0) {if(b%2==1)ans=chengfa(ans,n1);n1=chengfa(n1,n1);b/=2;}
    return ans;
}
int main() {
    int n,d;scanf("%d%d",&n,&d);
    a.len=1;a.a[1]=1;
    for(int i=1;i<d;i++) {a=pow(a,n);a=jiafa(a);}
    b=pow(a,n);b=jiafa(b);b=jianfa(b,a);
    for(int i=b.len;i>=1;i--)printf("%d",b.a[i]);printf("\n");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值