欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

[CQOI2017] 老C的键盘(树形dp + 组合数)

发布时间:2023/12/3 编程问答 44 豆豆
生活随笔 收集整理的这篇文章主要介绍了 [CQOI2017] 老C的键盘(树形dp + 组合数) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

problem

luogu-P3757

solution

observation:\text{observation}:observation: hi/2−hih_{i/2}-h_ihi/2hi 的大小关系,其实就是个二叉树的大小关系。

这很类似之前的排列 dpdpdp ,迁移过来,我们尝试 f(i,j):if(i,j):if(i,j):i 在子树内第 jjj 小的方案数。

当所有符号都是一个方向的时候,就是 [ZJOI2010]排列计数的题解,所以我们类比这里应该也是有组合数计算转移的。

同样是编号划分离散化的理解。

假设当前点为 uuu,儿子为 vvv,枚举 uuu 为其所在连通块的第 iii 小,vvv 为其所在联通块的第 jjj 小:

  • hu<hvh_u<h_vhu<hv

    考虑合并后,uuu 可能在新大小为 sizu+sizvsiz_u+siz_vsizu+sizv 的连通块中的排名。

    这就要看 vvv 所在联通块前 jjj 小的数与 huh_uhu 的关系了。

    但一定不会到 i+ji+ji+j

    所以,枚举合并后 uuu 的排名为 kkki≤k<i+ji\le k<i+jik<i+j

    f(u,k)←f(u,i)∗f(v,j)∗(k−1i−1)∗(sizu+sizv−ksizu−i)f(u,k)\leftarrow f(u,i)*f(v,j)*\binom{k-1}{i-1}*\binom{siz_u+siz_v-k}{siz_u-i}f(u,k)f(u,i)f(v,j)(i1k1)(sizuisizu+sizvk)

  • hu>hvh_u>h_vhu>hv

    转移方程式和原理同上一种情况,只是 kkk 的范围有所变化,i+j≤k≤i+sizvi+j\le k\le i+siz_vi+jki+sizv

时间复杂度为 O(n3)O(n^3)O(n3)

前缀和优化 O(n2)O(n^2)O(n2) 可以看[HEOI2013]SAO的题解。

code

#include <bits/stdc++.h> using namespace std; #define int long long #define mod 1000000007 #define maxn 105 char s[maxn]; int n; int c[maxn][maxn], f[maxn][maxn], g[maxn], siz[maxn];void dfs( int u ) {f[u][1] = siz[u] = 1;for( int o = 0;o <= 1;o ++ ) {int v = (u << 1) + o;if( v > n ) break;dfs( v );memcpy( g, f[u], sizeof( f[u] ) );memset( f[u], 0, sizeof( f[u] ) );for( int i = 1;i <= siz[u];i ++ )for( int j = 1;j <= siz[v];j ++ )if( s[v] == '>' ) {for( int k = i + j;k <= i + siz[v];k ++ )(f[u][k] += g[i] * c[k - 1][i - 1] % mod * f[v][j] % mod * c[siz[u] + siz[v] - k][siz[u] - i]) %= mod;}else {for( int k = i;k < i + j;k ++ )(f[u][k] += g[i] * c[k - 1][i - 1] % mod * f[v][j] % mod * c[siz[u] + siz[v] - k][siz[u] - i]) %= mod;}siz[u] += siz[v];} }signed main() {scanf( "%lld %s", &n, s + 2 );for( int i = 0;i <= n;i ++ ) {c[i][0] = c[i][i] = 1;for( int j = 1;j < i;j ++ )c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;}dfs( 1 );int ans = 0;for( int i = 1;i <= n;i ++ ) (ans += f[1][i]) %= mod;printf( "%lld\n", ans );return 0; }

总结

以上是生活随笔为你收集整理的[CQOI2017] 老C的键盘(树形dp + 组合数)的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。