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)表示两种颜色分别染的 ...
随机推荐
- Android JNI(一)——NDK与JNI基础
本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...
- Cocoapods 报警告Automatically assigning platform ios with version 9.0 on target....
Automatically assigning platform iOS with version 9.0 on target 你的工程名称 because no platform was speci ...
- Codeforces 894B - Ralph And His Magic Field
894B - Ralph And His Magic Field 思路: 当k为1时,如果n和m奇偶性不同,那么没有答案. 可以证明,在其他情况下有答案,且答案为2^(n-1)*(m-1),因为前n- ...
- Java数组的定义和使用
如果希望保存一组有相同类型的数据,可以使用数组. 数组的定义和内存分配 Java 中定义数组的语法有两种: type arrayName[]; type[] arrayName; type 为Java ...
- codeforces 484a//Bits// Codeforces Round #276(Div. 1)
题意:给出区间[ll,rr],求中间一个数二进制表示时一的个数最多. 写出ll和rr的二进制,设出现第一个不同的位置为pos(从高位到低位),找的数为x,那么为了使x在[ll,rr]内,前pos-1个 ...
- Android Studio apk打包,keystore.jks文件生成,根据keystore密钥获取SHA1安全码
keystore.jks文件生成,打包APK 选择Build > Generate Signed APK 出现如下弹框: 然后点击Create new...(创建的意思)出现另一个弹框,在做如下 ...
- Oracle性能诊断艺术-读书笔记(脚本execution_plans截图)
- dp练习(7)—— 最小和
3415 最小和 CodeVS原创 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 青铜 Bronze 题解 题目描述 Description 小浣熊松松来到文具店, ...
- dp入门求最大公共子序列
#include "bits/stdc++.h" using namespace std; ],b[]; ][]; int main() { cin >> a > ...
- 根据服务端生成的WSDL文件创建客户端支持代码的三种方式
第一种:使用wsimport是JDK自带的工具,来生成 生成java客户端代码常使用的命令参数说明: 参数 说明 -p 定义客户端生成类的包名称 -s 指定客户端执行类的源文件存放目录 -d 指定客户 ...