[CF509F]Progress Monitoring
题目大意:
给定一个树的DFS序$b_1,b_2,\ldots,b_n$($b$为$1\sim n$的一个排列且$b_1=1$)。同一个结点的子结点按照结点编号从小到大遍历。问有多少种可能的树的形态?
思路:
树形DP。
用$f[l][r]$标示DFS序$b_{l\sim r}$对应多少种树的形态。显然当$l=r$时,$f[l][r]=1$。转移方程为$f[l][r]=\sum_{l<m\le r且b_{m+1}<b_{l+1}}f[l+1][m]\times f[m][r]$。其中$f[l+1][m]$表示$b_{l+1\sim m}$构成树的方案数,$f[m][r]$表示$b_{m+1\sim r}$构成森林的方案数。这是一个$2D/1D$的动态规划,时间复杂度$O(n^3)$。
1 #include<cstdio> 2 #include<cctype> 3 typedef long long int64; 4 inline int getint() { 5 register char ch; 6 while(!isdigit(ch=getchar())); 7 register int x=ch^'0'; 8 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 9 return x; 10 } 11 const int N=501,mod=1e9+7; 12 int b[N],f[N][N]; 13 int dfs(const int &l,const int &r) { 14 if(f[l][r]) return f[l][r]; 15 if(l==r) return f[l][r]=1; 16 for(register int m=l+1;m<=r;m++) { 17 if(m!=r&&b[l+1]>b[m+1]) continue; 18 (f[l][r]+=(int64)dfs(l+1,m)*dfs(m,r)%mod)%=mod; 19 } 20 return f[l][r]; 21 } 22 int main() { 23 const int n=getint(); 24 for(register int i=1;i<=n;i++) b[i]=getint(); 25 printf("%d\n",dfs(1,n)); 26 return 0; 27 }