Codeforces gym101955 A【树形dp】
有n个大号和m个小号
然后需要对这些号进行匹配,一个大号最多匹配2个小号
匹配条件是大号和小号构成了前缀关系
字符串长度不超过10
问方案数
思路
因为要构成前缀关系
所以就考虑在trie树上dp
\(f_{i,j,k}\)表示i的子树中,还需要来自祖先的j个小号,并且有需要匹配但是没有匹配的小号k个
然后如果当前是一个大号节点
可以从子树中选一个小号
\(f_{u,j,k - 1}<=f_{v,j,k} * k\)
可以从子树中选两个小号
\(f_{u,j,k - 2}<=f_{v,j,k} * (\frac{k *(k - 1)}{2})\)
可以从祖先中选一个小号
\(f_{u,j+1, k}<=f_{u,j,k}\)
可以从祖先中选两个小号(因为在祖先中需要选择两次,避免重复计算这里除以2)
\(f_{u,j+2,k}<=f_{u,j,k}*\frac{1}{2}\)
可以从祖先选一个子树选一个
\(f_{u,j+1,k-1}<=f_{u,j,k}*k\)
这里我们考虑等价选择的多种方案的时候只在深度浅的地方算
然后实际上如果是小号节点,同理就好了
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
const int Mod = 1e9 + 7;
const int CHARSET_SIZE = 26;
int add(int a, int b) {
return (a += b) >= Mod ? a - Mod : a;
}
int mul(int a, int b) {
return 1ll * a * b % Mod;
}
struct Node {
int ch[CHARSET_SIZE], typ;
void init() {
typ = 0;
memset(ch, 0, sizeof(ch));
}
} p[N];
int tot = 0, n, m;
char c[N];
int f[N][12][22], g[N][12][22];
void init() {
tot = 1;
p[1].init();
}
void insert(char *s, int typ) {
int len = strlen(s + 1), u = 1;
for (int i = 1; i <= len; i++) {
int cur = s[i] - 'a';
if (!p[u].ch[cur])
p[p[u].ch[cur] = ++tot].init();
u = p[u].ch[cur];
}
p[u].typ = typ;
}
void dfs(int u) {
for (int i = 0; i <= 10; i++)
for (int j = 0; j <= 20; j++)
f[u][i][j] = g[u][i][j] = 0;
f[u][0][0] = 1;
for (int i = 0; i < CHARSET_SIZE; i++) {
int v = p[u].ch[i];
if (!v) continue;
dfs(v);
for (int j = 10; j >= 0; j--)
for (int k = 20; k >= 0; k--) if (f[u][j][k])
for (int l = 0; l <= 10 - j; l++)
for (int t = 0; t <= 20 - k; t++)
g[u][j + l][k + t] = add(g[u][j + l][k + t], mul(f[u][j][k], f[v][l][t]));
for (int j = 0; j <= 10; j++)
for (int k = 0; k <= 20; k++) {
f[u][j][k] = g[u][j][k];
g[u][j][k] = 0;
}
}
if (!p[u].typ) return;
for (int i = 0; i <= 10; i++) {
for (int j = 0; j <= 20; j++) if (f[u][i][j]) {
if (p[u].typ == 1) {
if (i + 1 <= 10)
g[u][i + 1][j] = add(g[u][i + 1][j], f[u][i][j]);
if (j - 1 >= 0)
g[u][i][j - 1] = add(g[u][i][j - 1], mul(j, f[u][i][j]));
if (i + 2 <= 10)
g[u][i + 2][j] = add(g[u][i + 2][j], mul((Mod + 1) >> 1, f[u][i][j]));
if (j - 2 >= 0)
g[u][i][j - 2] = add(g[u][i][j - 2], mul((j * (j - 1)) >> 1, f[u][i][j]));
if (i + 1 <= 10 && j - 1 >= 0)
g[u][i + 1][j - 1] = add(g[u][i + 1][j - 1], mul(j, f[u][i][j]));
} else {
if (i - 1 >= 0)
g[u][i - 1][j] = add(g[u][i - 1][j], mul(i, f[u][i][j]));
if (j + 1 <= 20)
g[u][i][j + 1] = add(g[u][i][j + 1], f[u][i][j]);
}
}
}
for (int i = 0; i <= 10; i++)
for (int j = 0; j <= 20; j++)
f[u][i][j] = add(f[u][i][j], g[u][i][j]);
}
void solve(int cas) {
init();
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%s", c + 1);
insert(c, 1);
}
for (int i = 1; i <= m; i++) {
scanf("%s", c + 1);
insert(c, 2);
}
dfs(1);
printf("Case #%d: %d\n", cas, f[1][0][0]);
}
int main() {
int T; scanf("%d", &T);
for (int i = 1; i <= T; i++)
solve(i);
return 0;
}
Codeforces gym101955 A【树形dp】的更多相关文章
- Codeforces Round #474-E(树形dp)
一.题目链接 http://codeforces.com/contest/960/problem/B 二.题意 给定一棵$N$个节点的树,每个节点的权值$V$.定义树中两点$u_1$和$u_m$的权值 ...
- Choosing Capital for Treeland CodeForces - 219D (树形DP)
传送门 The country Treeland consists of n cities, some pairs of them are connected with unidirectional ...
- Codeforces 431C - k-Tree - [树形DP]
题目链接:https://codeforces.com/problemset/problem/431/C 题意: 定义一个 $k$ 树,即所有节点都有 $k$ 个儿子节点,相应的这 $k$ 条边的权重 ...
- Codeforces 161D(树形dp)
\(dp[v][k]\)代表以\(v\)的子树为起点,以点\(v\)为终点长度为\(k\)的方案有多少种. 转移只需将子树加和:计算\(ans\)由两部分组成,一是\(dp[v][k]\),另一部分是 ...
- Codeforces 709E. Centroids 树形DP
题目链接:http://codeforces.com/contest/709/problem/E 题意: 给你一棵树,你可以任删一条边和加一条边,只要使得其仍然是一棵树,输出每个点是否都能成为重心 题 ...
- Codeforces Round #384 (Div. 2)D - Chloe and pleasant prizes 树形dp
D - Chloe and pleasant prizes 链接 http://codeforces.com/contest/743/problem/D 题面 Generous sponsors of ...
- Codeforces 743D:Chloe and pleasant prizes(树形DP)
http://codeforces.com/problemset/problem/743/D 题意:求最大两个的不相交子树的点权和,如果没有两个不相交子树,那么输出Impossible. 思路:之前好 ...
- codeforces 161D Distance in Tree 树形dp
题目链接: http://codeforces.com/contest/161/problem/D D. Distance in Tree time limit per test 3 secondsm ...
- codeforces 337D Book of Evil (树形dp)
题目链接:http://codeforces.com/problemset/problem/337/D 参考博客:http://www.cnblogs.com/chanme/p/3265913 题目大 ...
- codeforces 212E IT Restaurants(树形dp+背包思想)
题目链接:http://codeforces.com/problemset/problem/212/E 题目大意:给你一个无向树,现在用两种颜色去给这颗树上的节点染色.用(a,b)表示两种颜色分别染的 ...
随机推荐
- jq 命名空间
$('ul').on("click",function(){console.log('all');});$('ul').on("click.a",functio ...
- Python3 基本语法学习
1.查看Python版本及打印“Hellow World!”: 需要注意的是:在打印“Hello World”之前一定要先执行 python,否则会报无法 “无法初始化设备 PRN”,如图: 2.查看 ...
- php5.4 的 arm 交叉编译
./configure --prefix=/h1root/usr/php --host=arm-linux --enable-libxml --with-mysql=mysqlnd --with-my ...
- 关于c#除法运算的问题
https://blog.csdn.net/yxt1522916229/article/details/51107569/ 下面的示例可以验证一下问题: 例如: int m = 2; ...
- C#,ArcGIS Engine开发入门教程
C#,ArcGIS Engine开发入门教程 转自:http://blog.csdn.net/yanleigis/article/details/2233674 目录(?)[+] 五实现 一 加载A ...
- English trip -- VC(情景课)10 B Around the house 在家里
Vocablulary focus 核心词汇 cook play the guitar listen to music watch TV read magazines work in the gar ...
- English trip -- VC(情景课)5 C It's on Main Street 在主街上
Grammar focus 语法点: on, 在...上 next to , 旁边,周围 aross from , 对面 between 在...之间 in front of 在…前面 ...
- Many Easy Problem
转自hwk0518,不胜感谢,侵删.
- python-day34--并发编程之多线程
理论部分 一.什么是线程: 1.线程:一条流水线的工作过程 2.一个进程里至少有一个线程,这个线程叫主线程 进程里真正干活的就是线程 3.进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资 ...
- hdu 1175 bfs+priority_queue
连连看 如上图所示如果采用传统bfs的话,如果按照逆时针方向从(1,1)-->(3,4)搜索,会优先选择走拐四次弯的路径导致ans错误: Time Limit: 20000/10000 MS ( ...