正题
题目链接:https://jzoj.net/senior/#main/show/2755
题目大意
求有多少个nnn个点直径为ddd的标号树。
解题思路
定义fi,jf_{i,j}fi,j表示iii个点,深度不超过jjj的标号树数量。
然后有转移fi,j=∑k=1i−1Ci−2k−1∗k∗fk,j−1∗fi−k,jf_{i,j}=\sum_{k=1}^{i-1}C_{i-2}^{k-1}*k*f_{k,j-1}*f_{i-k,j}fi,j=k=1∑i−1Ci−2k−1∗k∗fk,j−1∗fi−k,j
然后对于输入,我们考虑根节点就是直径经过的点,那么我们分为两种情况讨论
- ddd是奇数,这个我们枚举两个树拼接在一起然后其它的点瞎连接即可
- ddd是偶数,将两棵树拼接在一起即可,那么答案为fn,d/2−fn,d/2+1?f_{n,d/2}-f_{n,d/2+1}?fn,d/2−fn,d/2+1?我们发现会有不合法情况,把不合法情况减去就好了
要高精度
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=51,P=1e6;
struct BNN{ll a[N],siz;
}ans,c[N][N],f[N][N],tmp;
BNN operator+(BNN a,BNN b){for(ll i=0;i<N;i++){a.a[i]=a.a[i]+b.a[i];a.a[i+1]+=a.a[i]/P;a.a[i]%=P;if(a.a[i])a.siz=i;}return a;
}
BNN operator-(BNN a,BNN b){for(ll i=0;i<N;i++){a.a[i]=a.a[i]-b.a[i];while(a.a[i]<0){a.a[i+1]--;a.a[i]+=P;}if(a.a[i])a.siz=i;}return a;
}
BNN operator*(BNN a,BNN b){BNN c;memset(c.a,0,sizeof(c.a));for(ll i=0;i<=a.siz;i++)for(ll j=0;j<=b.siz;j++)c.a[i+j]+=a.a[i]*b.a[j];c.siz=0;for(ll i=0;i<N;i++){c.a[i+1]+=c.a[i]/P;c.a[i]%=P;if(c.a[i])c.siz=i;}return c;
}
void write(BNN x){ll w=N-1;while(w&&!x.a[--w]);printf("%lld",x.a[w]);while((--w)>=0){if(x.a[w]<1e5)putchar('0');if(x.a[w]<1e4)putchar('0');if(x.a[w]<1e3)putchar('0');if(x.a[w]<1e2)putchar('0');if(x.a[w]<1e1)putchar('0');printf("%lld",x.a[w]);}putchar('\n');
}
int main()
{c[0][0].a[0]=1;for(ll i=1;i<N;i++){c[i][0].a[0]=1;for(ll j=1;j<=i;j++)c[i][j]=c[i-1][j]+c[i-1][j-1];}for(ll i=0;i<N;i++)f[1][i].a[0]=1;for(ll n=2;n<N;n++) for(ll d=1;d<N;d++){if(d>=n) {f[n][d]=f[n][d-1];continue;}for(ll i=1;i<n;i++){tmp.a[0]=i;f[n][d]=f[n][d]+(c[n-2][i-1]*tmp*f[i][d-1]*f[n-i][d]);n++;n--; }}ll n,d;while(scanf("%lld%lld",&n,&d)!=EOF){ll r=d/2;if(n==d){printf("0\n");continue;}if(!d){printf("%lld\n",(n==1));continue;}if(!r){printf("%lld\n",(n==2));continue;}memset(ans.a,0,sizeof(ans.a));ans.siz=0;if(d&1){for(ll i=r;i<n;i++){ll j=n-2-i;if(j<r) continue;ans=ans+((f[i+1][r]-f[i+1][r-1])*(f[j+1][r]-f[j+1][r-1])*c[n-2][i]);}ans=ans*c[n][2];}else{ans=f[n][r]-f[n][r-1];if(r>=2){for(ll i=r;i<=n-1;i++){tmp.a[0]=i;ans=ans-(tmp*(f[i][r-1]-f[i][r-2])*c[n-1][i]*f[n-i][r-1]);}}tmp.a[0]=n;ans=ans*tmp;}write(ans);}
}