树(prufer序,dp,排列组合)
2018-01-01 21:10
323 查看
Description
有nn个点,第ii个点的限制为度数不能超过aiai。现在对于每一个s(1≤s≤n)s(1≤s≤n),问从这nn个点中选出ss个点组成有标号无根树的方案数mod1004535809mod1004535809。Solution
参考博客由于每一个prufer序对应了一棵唯一的树且prufer序中每个数的出现次数为该节点的度−1−1,考虑在prufer序上进行dp。
设dpi,j,kdpi,j,k表示前ii个节点中,选了jj个节点,一共填了kk位。
已知选了ss个节点,每个点的出现次数为CiCi,则方案数为:s!C1!C2!…Cs!s!C1!C2!…Cs!
为了方便,我们将dpi,j,kdpi,j,k除以s!s!,那么得到转移方程就非常显然了:
(f[i + 1][j][k] += f[i][j][k]) %= Ha;//不选第i+1个点 (f[i + 1][j + 1][k + l] += f[i][j][k] * ifac[l] % Ha) %= Ha;//将l个(i+1)点加入prufer序 //ifac[l]为l阶乘的逆元
Code
/************************** Happy New Year! Au: Hany01 Date: Jan 1st, 2018 Prob: tree Email: hany01@foxmail.com **************************/ #include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int, int> PII; #define rep(i, j) for (register int i = 0, i##_end_ = (j); i < i##_end_; ++ i) #define For(i, j, k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i) #define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i) #define Set(a, b) memset(a, b, sizeof(a)) #define Cpy(a, b) memcpy(a, b, sizeof(a)) #define fir first #define sec second #define pb(a) push_back(a) #define mp(a, b) make_pair(a, b) #define ALL(a) (a).begin(), (a).end() #define SZ(a) ((int)(a).size()) #define INF (0x3f3f3f3f) #define INF1 (2139062143) #define Ha (1004535809) template <typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; } template <typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; } inline int read() { register int _, __; register char c_; for (_ = 0, __ = 1, c_ = getchar(); c_ < '0' || c_ > '9'; c_ = getchar()) if (c_ == '-') __ = -1; for ( ; c_ >= '0' && c_ <= '9'; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48); return _ * __; } inline void File() { freopen("tree.in", "r", stdin); freopen("tree.out", "w", stdout); } template<typename T> inline void mod(T &x) { if (x >= Ha) x -= Ha; } const int maxn = 105; int n, a[maxn]; ll fac[maxn], ifac[maxn], f[maxn][maxn][maxn]; inline ll Pow(ll a, ll b) { ll Ans = 1; for ( ; b; b >>= 1, a = a * a % Ha) if (b & 1) (Ans *= a) %= Ha; return Ans; } inline void Init() { n = read(); For(i, 1, n) a[i] = read(); fac[0] = 1; For(i, 1, n) fac[i] = fac[i - 1] * i % Ha; ifac = Pow(fac , Ha - 2); Fordown(i, n, 1) ifac[i - 1] = ifac[i] * i % Ha; } int main() { File(); Init(); //dp[i][j][k] means till the i_th node, you have choosed j kinds of them and k nodes altogether. f[0][0][0] = 1; rep(i, n) rep(j, i + 1) rep(k, n - 1) { if (!f[i][j][k]) continue; mod(f[i + 1][j][k] += f[i][j][k]); rep(l, min(n - k - 1, a[i + 1])) mod(f[i + 1][j + 1][k + l] += f[i][j][k] * ifac[l] % Ha); } printf("%d", n); For(i, 2, n) cout << ' ' << f [i][i - 2] * fac[i - 2] % Ha; putchar('\n'); return 0; } //十年磨一剑,霜刃未曾试。 // -- 贾岛《剑客 / 述剑》
相关文章推荐
- fjnu2013校赛E(数位dp,排列组合)
- HDU 1799 循环多少次?(排列组合,dp)
- 【prufer序】树-dp-组合数学
- BZOJ 2111: [ZJOI2010]Perm 排列计数|组合数学|Lucas定理|DP
- 【HDU5896 2016 ACM ICPC Asia Regional Shenyang Online E】【DP 排列组合 分治ntt】Running King n个点构成含环无向图的方案数.cp
- 【HDU】 4832 Chess 排列组合 DP
- hdu 1799 循环多少次(DP,排列组合Cn(m))
- 排列组合(二) - HDU 1436 dp
- HDU 6143 排列组合 - DP
- HDU-4661 Message Passing 树形DP,排列组合
- zoj 3725 dp求排列组合数
- nyoj1076-方案数量 【排列组合 dp】
- HDU 5396 Expression(区间DP,排列组合)
- BZOJ 1072: [SCOI2007]排列perm [DP 状压 排列组合]
- zoj 3747 排列组合dp
- [Bzoj3193][JLOI2013]地形生成 (排列组合 + DP)
- PID371 / [AHOI1997]彩旗飘飘 排列组合加DP
- 【经典】【DP】计算得分的排列方式和组合方式
- HDU 5151 Sit sit sit 区间DP + 排列组合
- 【ZJOI2017 Round1练习&BZOJ4767】D1T3 两双手(排列组合,DP)