题面

题解

首先将所有相等的用并查集缩点,然后会发现题目有一个很有用的性质:

对每张图片\(i\),小D都最多只记住了某一张质量不比\(i\)差的另一张图片\(K_i\)。

于是将\(K_i\)作为\(i\)的父亲节点,对于\(K_i = 0\)的点,令\(i\)的父亲为\(n + 1\)即可。

开始树形\(dp\),设\(f[x][i]\)表示\(dp\)到点\(x\),有\(i - 1\)个小于号的方案数。

那么我们可以推出一个式子:

\[f[x][i] = \sum_{to \in son(i), j, k} f'[x][j] \times f[to][k] \times \xi
\]

其中\(\xi\)是表示\(j\)段和\(k\)段合并成\(i\)段的方案数。

我们考虑如何求余项\(\xi\),设\(f[x]\)的质量序列为\(A\),\(f'[x]\)的质量序列为\(B\),\(f[to]\)的质量序列为\(C\)。

\(A\)的每一段可以只包含\(B\)的一段或者\(C\)的一段,也可以同时包含,但不能为空。特殊地,\(A\)的第一段只能包含节点\(x\)。

于是\(\xi\)相当于先枚举\(B\)中的\(j - 1\)段在\(A\)中放的位置,方案数为\(\binom{i - 1}{j - 1}\),然后将\(C\)的\(i - j\)段放在\(A\)中剩下的位置,使得每一段都不为空。现在\(C\)中还有\(k - i + j\)段要与\(B\)中的段合并,方案数为\(\binom{j - 1}{k - i + j}\)。

于是:

\[\xi = \binom{i - 1}{j - 1} \times \binom{j - 1}{k - i + j}
\]

最后答案为\(\sum_{i = 1}^{\mathrm{size}(n + 1)} f[n + 1][i]\)

复杂度:因为每个点对只会在LCA处算\(\mathrm{O}(n)\)次,于是复杂度是\(\mathrm{O}(n^3)\)

代码

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define RG register inline int read()
{
int data = 0, w = 1; char ch = getchar();
while(ch != '-' && (!isdigit(ch))) ch = getchar();
if(ch == '-') w = -1, ch = getchar();
while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
return data * w;
} inline char get()
{
char ch = getchar();
while(ch != '<' && ch != '=') ch = getchar();
return ch;
} const int N(105), Mod(1e9 + 7), M(100);
struct edge { int next, to; } e[N << 1];
int n, m, X[N], Y[N], fa[N], eq[N], size[N], e_num;
int belong[N], cnt[N], head[N], C[N][N], f[N][N];
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
inline void add_edge(int from, int to)
{
e[++e_num] = (edge) {head[from], to}; head[from] = e_num;
e[++e_num] = (edge) {head[to], from}; head[to] = e_num;
} inline int merge(int x, int y)
{
int fx = find(x), fy = find(y);
fa[fx] = fy; return fx == fy;
} void dfs(int x, int _f)
{
static int g[N]; size[x] = f[x][1] = 1;
for(RG int p = head[x]; p; p = e[p].next)
{
int to = e[p].to; if(to == _f) continue;
dfs(to, x); std::fill(g + 1, g + n + 1, 0);
for(RG int i = 1; i <= size[x] + size[to]; i++)
for(RG int j = 1; j <= size[x]; j++)
for(RG int k = 1; k <= size[to]; k++)
{
int t = k - i + j; if(t < 0) continue;
g[i] = (g[i] + 1ll * f[x][j] * f[to][k] % Mod *
C[i - 1][j - 1] % Mod * C[j - 1][t]) % Mod;
}
size[x] += size[to];
std::copy(g + 1, g + size[x] + 1, f[x] + 1);
}
} int main()
{
C[0][0] = 1;
for(RG int i = 1; i <= M; i++)
{
C[i][0] = C[i][i] = 1;
for(RG int j = 1; j < i; j++)
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % Mod;
}
n = read(), m = read();
for(RG int i = 1; i <= n; i++) fa[i] = i;
for(RG int i = 1; i <= m; i++)
X[i] = read(), eq[i] = get() == '=', Y[i] = read();
for(RG int i = 1; i <= m; i++) if(eq[i]) fa[find(X[i])] = find(Y[i]);
for(RG int i = 1; i <= n; i++) belong[i] = find(i);
for(RG int i = 1; i <= n; i++) fa[i] = i;
for(RG int i = 1; i <= m; i++) if(!eq[i])
{
add_edge(belong[X[i]], belong[Y[i]]), ++cnt[belong[Y[i]]];
if(merge(belong[X[i]], belong[Y[i]])) return puts("0") & 0;
}
for(RG int i = 1; i <= n; i++)
if(belong[i] == i && !cnt[i]) add_edge(n + 1, i);
int ans = 0; dfs(n + 1, 0);
for(RG int i = 1; i <= size[n + 1]; i++)
ans = (ans + f[n + 1][i]) % Mod;
printf("%d\n", ans);
return 0;
}

【HNOI2015】实验比较的更多相关文章

  1. 【BZOJ4013】[HNOI2015]实验比较(动态规划)

    [BZOJ4013][HNOI2015]实验比较(动态规划) 题面 BZOJ 洛谷 题解 看题目意思就是给你一棵树,连边表示强制顺序关系.然后你要给点染色,在满足顺序关系的情况下,将序列染成若干个颜色 ...

  2. 4013: [HNOI2015]实验比较

    4013: [HNOI2015]实验比较 链接 分析: 首先把等号用并查集合并起来. 由于只存在最多一个质量不比i差的数,发现这是森林.若x<y,连边x->y.于是建虚拟根节点0. 然后树 ...

  3. [BZOJ4013][HNOI2015]实验比较(树形DP)

    4013: [HNOI2015]实验比较 Time Limit: 5 Sec  Memory Limit: 512 MBSubmit: 756  Solved: 394[Submit][Status] ...

  4. bzoj 4013: [HNOI2015]实验比较

    Description 小D 被邀请到实验室,做一个跟图片质量评价相关的主观实验.实验用到的图片集一共有 N 张图片,编号为 1 到 N.实验分若干轮进行,在每轮实验中,小 D会被要求观看某两张随机选 ...

  5. [HNOI2015]实验比较

    Description 小D 被邀请到实验室,做一个跟图片质量评价相关的主观实验.实验用到的图片集一共有 N 张图片,编号为 1 到 N.实验分若干轮进行,在每轮实验中,小 D会被要求观看某两张随机选 ...

  6. P3240 [HNOI2015]实验比较 树形DP

    \(\color{#0066ff}{ 题目描述 }\) 小D 被邀请到实验室,做一个跟图片质量评价相关的主观实验.实验用到的图片集一共有 \(N\) 张图片,编号为 \(1\) 到\(N\).实验分若 ...

  7. BZOJ4013 : [HNOI2015]实验比较

    首先用并查集将等号缩点,然后拓扑排序判断有没有环,有环则无解,否则通过增加超级源点$0$,可以得到一棵树. 设$f[x][y]$表示$x$子树里有$y$种不同的数字的方案数,由底向上DP. 对于当前点 ...

  8. luogu P3240 [HNOI2015]实验比较

    传送门 首先根据题目条件,题目中如果是=的点可以缩起来,然后\(a<b\)连边\(a\rightarrow b\),而且所有点入度为最多1,那么判掉有环的不合法情况,题目中的依赖关系就是一颗外向 ...

  9. 【BZOJ】4013: [HNOI2015]实验比较

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4013 中第i 条涉及的图片对为(KXi, Xi),判断要么是KXi < Xi ,要么 ...

  10. 【LG3240】[HNOI2015]实验比较

    题面 洛谷 题解 30pts 爆搜即可. 100pts 题意描述里有一句:"对每张图片\(i\),小\(D\)都最多只记住了某一张质量不比\(i\)差的另一张图片\(K_i\)." ...

随机推荐

  1. 在table中选中某条数据,让其显示对应详细信息

    在第一个页面中使用 ccms.dialog.open({url:url+$(this).attr("code"),id:"dialogPic",width:10 ...

  2. GBK与UTF-8编码错误转换后,无法再正确恢复

    字符集错误转换导致的问题 UTF-8格式编码的字节流,按GBK字符集转换为字符串,会出现乱码,这很正常.但将其重新转为字节流,再用UTF-8字符集转为字符串,还是乱码.这就让我产生了疑惑,虽然使用错误 ...

  3. centos7.4 nfs-2.3.2

    http://www.linuxfromscratch.org/blfs/view/svn/basicnet/libtirpc.html 注释:安装环境centos7.4;   安装完软件成后会升级系 ...

  4. November 16th 2016 Week 47th Wednesday

    Success is falling nine times and getting up ten. 成功就是哪怕跌倒九次,也要在第十次爬起来. For most of us, we may choos ...

  5. SAP 前端技术的演化史简介

    Jerry之前曾经写过一篇微信公众号文章,题目叫<> 关注我的公号"汪子熙"后,在历史菜单"前端开发相关"里即可找到这篇文章: 该文章简单回顾了SA ...

  6. Promise & Deferred Objects in JavaScript Pt.2: in Practice

    原文:http://blog.mediumequalsmessage.com/promise-deferred-objects-in-javascript-pt2-practical-use Intr ...

  7. IO多路复用(select)

    select在操作系统内部,维护了一个for循环,检测对象是否变化.select在各种平台都可使用,但效率不高.select对监听的个数是有限制的(1024) poll与select相同,但是没有监听 ...

  8. mybatis中使用in查询时的注意事项

    1. 当查询的参数只有一个时 findByIds(List<Long> ids)  1.a 如果参数的类型是List, 则在使用时,collection属性要必须指定为 list < ...

  9. 在Ubuntu Desktop中安装软件

    1. 安装好虚拟机后,可以先打开firefox,看是否可以访问外部的网页. 2. 如果在公司内网,可能访问不起,需要添加代理,确保可以访问外部的网页. 3. 更新软件源 sudo apt update ...

  10. RLE Iterator LT900

    Write an iterator that iterates through a run-length encoded sequence. The iterator is initialized b ...