CF724F Uniformly Branched Trees
有根树可以统计。无根树难以统计。因为可以换根。
所以不让换根:只要两个无根树在重心位置不同构,就一定不同构
每个本质不同的树在重心位置统计上。
f[i][j][k]i个点根节点度数j,最大子树不超过k。枚举k大小的子树个数转移。
重心两个?
特殊考虑。两端f[n/2][d-1][n/2-1]=x,x*(x-1)/2+x
边界考虑到。
#include<bits/stdc++.h> #define reg register int #define il inline #define numb (ch^'0') using namespace std; typedef long long ll; il void rd(int &x){ char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } namespace Miracle{ const int N=1005; int mod,n,d; int f[N][11][N]; int jie[11],inv[11]; int qm(int x,int y){ int ret=1;while(y){ if(y&1) ret=(ll)ret*x%mod;x=(ll)x*x%mod;y>>=1; }return ret; } int dp(int i,int j,int k){ //cout<<" dp "<<i<<" "<<j<<" "<<k<<endl; if(f[i][j][k]!=-1) return f[i][j][k]; if(i==1) { if(j==d-1||!j) return f[i][j][k]=1; return f[i][j][k]=0; } if(i==0){ if(k==0&&j==0) return f[i][j][k]=1; else return f[i][j][k]=0; } if(j>i-1) return f[i][j][k]=0; if(i>1&&k==0) return f[i][j][k]=0; int C=1; int ret=0; int tmp=dp(k,d-1,k-1); // cout<<" tmp "<<tmp<<" i j k "<<i<<" "<<j<<" "<<k<<endl; for(reg m=0;m<=j&&m*k<=i-1;++m){ ret=(ret+(ll)dp(i-m*k,j-m,k-1)*C%mod*inv[m]%mod)%mod; C=(ll)C*(tmp-1+m+1)%mod; } //cout<<" ret "<<ret<<endl; return f[i][j][k]=ret; } int main(){ rd(n);rd(d);rd(mod); if(n<=2){ puts("1");return 0; } memset(f,-1,sizeof f); jie[0]=1; for(reg i=1;i<=10;++i) jie[i]=(ll)jie[i-1]*i%mod; inv[10]=qm(jie[10],mod-2); for(reg i=9;i>=0;--i) inv[i]=(ll)inv[i+1]*(i+1)%mod; ll ans=0; ans=(ans+dp(n,d,(n-1)/2)); // cout<<"ans1 ------"<<ans<<endl; if(n%2==0){ ll tmp=0; tmp=dp(n/2,d-1,n/2-1); ans=(ans+(tmp*(tmp+1)/2%mod))%mod; } printf("%I64d",ans); return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2019/3/3 18:21:10 */
在某个位置为代表统计所有情况,
既可以不重不漏,还可以有的放矢