bzoj1089严格n元树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1089

这是一种套路:记录“深度为 i ”的话,转移需要讨论许多情况;所以可以记录成“深度<=i”!!!

  (这种前缀和的样子得到答案也很方便,就是 f [ d ] - f [ d -1 ]。)

这样的话把根节点拿出来,剩下的就是n个深度为 i - 1 的子树了。

当然,每个深度的情况里要包含“什么节点也没有”的情况,才能正确转移。所以要+1。

1.重载运算符好方便!  2.输出的时候要注意不能吞0!学了一招。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int rad=1000;
int n,d;
struct data{
    int v[5005],l;
}f[30];
data operator*(data a,data b)
{
    data 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]>=rad)
        {
            if(i==c.l)c.l++,c.v[c.l]=0;
            c.v[i+1]+=c.v[i]/rad;
            c.v[i]%=rad;
        }
    while(!c.v[c.l]&&c.l>1)c.l--;//c.l>1
    return c;
}
data operator^(data a,int b)
{
    data c;
    c.v[1]=1;c.l=1;
    while(b)
    {
        if(b&1)c=c*a;
        a=a*a;b>>=1;
    }
    return c;
}
data operator+(data a,int b)
{
    a.v[1]+=b;int k=1;
    while(a.v[k]>=rad)a.v[k+1]+=a.v[k]/rad,a.v[k]%=rad,k++;
    a.l=max(a.l,k);
    return a;
}
data operator-(data a,data b)
{
    for(int i=a.l;i;i--)
    {
        a.v[i]-=b.v[i];
        if(a.v[i]<0)a.v[i]+=rad,a.v[i+1]--;
    }
    while(!a.v[a.l]&&a.l>1)a.l--;
    return a;
}
void print(data a)
{
    printf("%d",a.v[a.l]);
    for(int i=a.l-1;i;i--)printf("%03d",a.v[i]);
}
int main()
{
    scanf("%d%d",&n,&d);
    if(!d){printf("1");return 0;}
    f[0]=f[0]+1;
    for(int i=1;i<=d;i++)
        f[i]=(f[i-1]^n)+1;
    print(f[d]-f[d-1]);
    return 0;
}
原文地址:https://www.cnblogs.com/Narh/p/9135262.html