\(\color{#0066ff}{ 题目描述 }\)

小D 被邀请到实验室,做一个跟图片质量评价相关的主观实验。实验用到的图片集一共有 \(N\) 张图片,编号为 \(1\) 到\(N\)。实验分若干轮进行,在每轮实验中,小 D会被要求观看某两张随机选取的图片, 然后小D 需要根据他自己主观上的判断确定这两张图片谁好谁坏,或者这两张图片质量差不多。 用符号”\(<\)“、”\(>\)“和”\(=\)“表示图片 \(x\)和\(y\)(\(x\)、\(y\)为图片编号)之间的比较:

如果上下文中 \(x\) 和 \(y\) 是图片编号,则 \(x<y\) 表示图片 xx”质量优于“\(y\),\(x>y\) 表示图片 \(x\)”质量差于“\(y\),\(x=y\)表示图片 \(x\)和 \(y\)”质量相同“;

也就是说,这种上下文中,”\(<\)“、”\(>\)“、”\(=\)“分别是质量优于、质量差于、质量相同的意思;在其他上下文中,这三个符号分别是小于、大于、等于的含义。图片质量比较的推理规则(在 x和y是图片编号的上下文中):

(1)\(x < y\)等价于 \(y > x\)。

(2)若 \(x < y\) 且\(y = z\),则\(x < z\)。

(3)若\(x < y\)且 \(x = z\),则 \(z < y\)。

(4)\(x=y\)等价于 \(y=x\)。

(5)若\(x=y\)且 \(y=z\),则\(x=z\)。

实验中,小 D 需要对一些图片对\((x, y)\),给出 \(x < y\) 或 \(x = y\) 或 \(x > y\) 的主观判断。小D 在做完实验后, 忽然对这个基于局部比较的实验的一些全局性质产生了兴趣。在主观实验数据给定的情形下,定义这 \(N\) 张图片的一个合法质量序列为形如”\(x_1\) \(R_1\) \(x_2\) \(R_2\) \(x_3\) \(R_3\) ...... \(x_{N-1}\) \(R_{N-1}\) \(x_N\)“的串,也可看作是集合{ \(x_i{ R_i x_{i+1} |1\leq i\leq N-1\}}\),其中 \(x_i\)为图片编号,\(x_1\),\(x_2\),...,\(x_N\)两两互不相同(即不存在重复编号),\(R_i\)为\(<\)或\(=\),”合法“是指这个图片质量序列与任何一对主观实验给出的判断不冲突。

例如: 质量序列\(3 < 1 = 2\) 与主观判断”\(3 > 1,3 = 2\)“冲突(因为质量序列中 \(3<1\) 且\(1=2\),从而\(3<2\),这与主观判断中的 \(3=2\) 冲突;同时质量序列中的 \(3<1\) 与主观判断中的 \(3>1\) 冲突) ,但与主观判断”\(2 = 1\),\(3 < 2\)“ 不冲突;因此给定主观判断”\(3>1\),\(3=2\)“时,\(1<3=2\) 和\(1<2=3\) 都是合法的质量序列,\(3<1=2\) 和\(1<2<3\)都是非法的质量序列。由于实验已经做完一段时间了,小D 已经忘了一部分主观实验的数据。对每张图片 \(i\),小 D 都最多只记住了某一张质量不比 \(i\) 差的另一张图片 \(K_i\)。这些小 D 仍然记得的质量判断一共有 \(M\) 条(\(0 \leq M \leq N\)),其中第\(i\) 条涉及的图片对为(\(K_{X_i}, X_i\)),判断要么是\(K_{X_i} < X_i\) ,要么是\(K_{X_i} = X_i\),而且所有的\(X_i\)互不相同。小D 打算就以这\(M\) 条自己还记得的质量判断作为他的所有主观数据。

现在,基于这些主观数据,我们希望你帮小 D 求出这 N 张图片一共有多少个不同的合法质量序列。

我们规定:如果质量序列中出现”\(x = y\)“,那么序列中交换 \(x\)和\(y\)的位置后仍是同一个序列。因此: \(1<2=3=4<5\) 和\(1<4=2=3<5\) 是同一个序列, \(1 < 2 = 3\) 和 \(1 < 3 = 2\) 是同一个序列,而\(1 < 2 < 3\) 与\(1 < 2 = 3\)是不同的序列,\(1<2<3\)和\(2<1<3\) 是不同的序列。由于合法的图片质量序列可能很多, 所以你需要输出答案对\(10^9 + 7\) 取模的结果

\(\color{#0066ff}{输入格式}\)

第一行两个正整数\(N\),\(M\),分别代表图片总数和小D仍然记得的判断的条数;接下来\(M\)行,每行一条判断,每条判断形如“\(x < y\)“或者“\(x = y\)“。

\(\color{#0066ff}{输出格式}\)

输出仅一行,包含一个正整数,表示合法质量序列的数目对 \(10^9+7\)取模的结果。

\(\color{#0066ff}{输入样例}\)

5 4
1 < 2
1 < 3
2 < 4
1 = 5

\(\color{#0066ff}{输出样例}\)

5

\(\color{#0066ff}{数据范围与提示}\)

不同的合法序列共5个,如下所示:

1 = 5 < 2 < 3 < 4
1 = 5 < 2 < 4 < 3
1 = 5 < 2 < 3 = 4
1 = 5 < 3 < 2 < 4
1 = 5 < 2 = 3 < 4
100%的数据满足N<=100。

\(\color{#0066ff}{ 题解 }\)

首先,用ufs把等号的点缩起来(没影响),然后开始判无解

因为每个点小于的信息最多只有一个,所以可以用并查集判断无解

而且根据这个条件,可以连边弄出一个森林,显然我们需要一个超级源建立一棵树

然后可以愉快的开始树形DP了

常规的设法,\(f[i]\)表示以i为根子树的方案

但是发现并不行

因为两个序列合并的时候可以是小于,还可以是相等

也就是说对于i的子树的两个不同的节点uv,他们的子树可能存在两个节点相等的情况

设\(f[u][i]\)表示\(u\)的子树里,分成\(i\)段(也就是共有\(i-1\)个小于号把质量序列分成了\(i\)个部分,每个部分里的图片质量相等)的方案数,然后做一次树形背包DP(当前枚举到了\(u\)的子节点\(v\),f'表示枚举到子节点\(v\)前的DP值):

\(f[u][i]=\sum_{j,k}f'[u][j]\times f[v][k]\times C_{i−1}^{j−1}\times C_{j−1}^{k−i+j}\)

后面两个是把j段和k段合并为i段的方案

设\(f[u]\)的质量序列为\(A\),\(f'[u]\)的质量序列为\(B\),\(f[v]\)的质量序列为\(C\)。

\(A\)中的每一段可以只包含\(B\)中的一段,可以只包含\(C\)中的一段,也可以有\(B\)和\(C\)各一段合并而成,但不能为空。特殊地,\(A\)的第一段只能包含节点\(u\)。

相当于先枚举\(B\)中的\(j-1\)段在\(A\)中放的位置,方案数为\(C_{i-1}^{j-1}\),然后把\(C\)中的\(i-j\)段放到\(A\)中剩下的位置,使每一段都不为空。现在\(C\)还剩下\(k-i+j\)个段,他们需要与\(B\)中的段合并,方案数\(C_{j-1}^{k-i+j}\)。

最后总答案为 \(\sum_{i}f[n+1][i]\)。

#include<bits/stdc++.h>
#define LL long long
LL in() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const int mod = 1e9 + 7;
const int maxn = 520;
LL f[maxn][maxn], g[maxn], C[maxn][maxn];
int fa[maxn], siz[maxn], du[maxn], bel[maxn];
bool vis[maxn];
struct node {
int to;
node *nxt;
node(int to = 0, node *nxt = NULL): to(to), nxt(nxt) {}
void *operator new(size_t) {
static node *S = NULL, *T = NULL;
return (S == T) && (T = (S = new node[1024]) + 1024), S++;
}
};
struct E {
int x, y, tp;
}e[maxn];
node *head[maxn];
void add(int from, int to) {
head[from] = new node(to, head[from]);
}
char getch() {
char ch = getchar();
while(ch != '<' && ch != '=') ch = getchar();
return ch;
}
int n, m;
void predoit() {
C[0][0] = 1;
for(int i = 1; i <= n; i++) {
C[i][0] = 1;
for(int j = 1; j <= i; j++) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
}
}
int findset(int x) { return x == fa[x]? fa[x] : fa[x] = findset(fa[x]); }
void dfs(int x) {
siz[x] = 1, f[x][1] = 1;
for(node *i = head[x]; i; i = i->nxt) {
dfs(i->to);
for(int v = 1; v <= n; v++) g[v] = 0;
for(int v = 1; v <= siz[x] + siz[i->to]; v++)
for(int j = 1; j <= siz[x]; j++)
for(int k = 1; k <= siz[i->to]; k++) {
int p = k - v + j;
if(p < 0) continue;
(g[v] += f[x][j] * f[i->to][k] % mod * C[v - 1][j - 1] % mod * C[j - 1][p] % mod) %= mod;
}
for(int v = 1; v <= siz[x] + siz[i->to]; v++) f[x][v] = g[v];
siz[x] += siz[i->to];
}
} int main() {
n = in(), m = in();
predoit();
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i = 1; i <= m; i++) e[i].x = in(), e[i].tp = getch() == '=', e[i].y = in();
for(int i = 1; i <= m; i++) {
if(!e[i].tp) continue;
int xx = findset(e[i].x);
int yy = findset(e[i].y);
if(xx != yy) fa[xx] = yy;
}
for(int i = 1; i <= n; i++) vis[bel[i] = findset(i)] = true;
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i = 1; i <= m; i++) {
if(e[i].tp) continue;
add(bel[e[i].x], bel[e[i].y]), du[bel[e[i].y]]++;
int xx = findset(bel[e[i].x]), yy = findset(bel[e[i].y]);
if(xx == yy) return puts("0"), 0;
fa[xx] = yy;
}
for(int i = 1; i <= n; i++) if(!du[i] && vis[i]) add(n + 1, i);
dfs(n + 1);
LL ans = 0;
for(int i = 1; i <= n + 1; i++) (ans += f[n + 1][i]) %= mod;
printf("%lld\n", ans);
return 0;
}

P3240 [HNOI2015]实验比较 树形DP的更多相关文章

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

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

  2. [HNOI2015]实验比较 树形dp+组合数学

    在合并的时候有可以加等于,或者继续用小于, 比如siz[x]和siz[y]合并,小于的区间为max(siz[x],siz[y])<=k<=siz[x]+siz[y], 然后就是合并成多少个 ...

  3. BZOJ 4013/Luogu P3240 [HNOI2015] 实验比较 (树形DP)

    题目传送门 分析 放一个dalao博客: xyz32768 的博客,看完再回来看本蒟蒻的口胡吧(其实嘛-不回来也行) 精髓是合并的方案数的计算,至于为什么是Ci−1j−1\large C_{i-1}^ ...

  4. luogu P3240 [HNOI2015]实验比较

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

  5. 4013: [HNOI2015]实验比较

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

  6. [BZOJ3167][P4099][HEOI2013]SAO(树形DP)

    题目描述 Welcome to SAO ( Strange and Abnormal Online).这是一个 VR MMORPG, 含有 n 个关卡.但是,挑战不同关卡的顺序是一个很大的问题. 有 ...

  7. 树形DP——动态规划与数据结构的结合,在树上做DP

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是算法与数据结构的第15篇,也是动态规划系列的第4篇. 之前的几篇文章当中一直在聊背包问题,不知道大家有没有觉得有些腻味了.虽然经典的文 ...

  8. poj3417 LCA + 树形dp

    Network Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4478   Accepted: 1292 Descripti ...

  9. COGS 2532. [HZOI 2016]树之美 树形dp

    可以发现这道题的数据范围有些奇怪,为毛n辣么大,而k只有10 我们从树形dp的角度来考虑这个问题. 如果我们设f[x][k]表示与x距离为k的点的数量,那么我们可以O(1)回答一个询问 可是这样的话d ...

随机推荐

  1. [JAVA反序列化DEMO]利用RMI进行反序列化一键启动工具

    功能: 命令行启动jar包,用户自定义启动RMI端口.默认内置Apache Commons Collections.只需一键启动即可测试java反序列化漏洞. 启动服务: [root@sevck_v3 ...

  2. LNMP 1.2 Nginx编译安装

    Nginx官网是:nginx.org 下载稳定版本 cd /usr/local/src wget http://nginx.org/download/nginx-1.8.0.tar.gz tar zx ...

  3. 3-3 zookeeper的作用体现

    zookeeper比较重要的一个模式:选举模式,这也是高可用的一个体现.公司的董事长.副董事长.董事会常理员以及老总和副总,他们并不会乘坐同一班飞机,而是会分为两班或者三班飞机一起去,也就是我们所谓的 ...

  4. day17-jdbc 6.Connection介绍

    package cn.itcast.jdbc; import com.mysql.jdbc.Connection; import java.sql.DriverManager; import java ...

  5. Codeforces #505(div1+div2) B Weakened Common Divisor

    题意:给你若干个数对,每个数对中可以选择一个个元素,问是否存在一种选择,使得这些数的GCD大于1? 思路:可以把每个数对的元素乘起来,然后求gcd,这样可以直接把所有元素中可能的GCD求出来,从小到大 ...

  6. g2o20160430下的csparse文件夹内的CMakeLists.txt

    1. g2o20160430下的csparse文件夹内的CMakeLists.txt cmake_minimum_required(VERSION 2.6) PROJECT(csparse) SET( ...

  7. ZROI #88

    传送门 分析 我们考虑把每个A[i]考虑为山峰的高度,每次的B考虑为海平面 于是我们知道对于A[i]和A[i-1],如果A[i-1]<A[i]则在A[i-1]<B<=A[i]时会使陆 ...

  8. 每日一Git计划启动

    效仿某大神,每日一Git,初次启动,维时30天 规范: 1. 不能提交纯属搞笑灌水的 2. 可以提交ACM题目代码 3. 想不到了..靠自觉的东西,对自己有提升的就做,没提升纯属刷数据的就不算吧.. ...

  9. Qemu虚拟机 玩树莓派最新版系统 (截止2017-04-10)

    Qemu虚拟机可以玩 树莓派,大家都知道了吧.可是网上的教程好老,都是2012年的.我按照教程下载了最新版版本的树莓派系统怎么也跑不起来. 研究了好久,终于找到一个简单的方法,特意分享出来.转载请注意 ...

  10. 数据结构 hbb(汉堡包)

    数据结构 hbb(汉堡包) 问题描述 汉堡包有收集汉犇犇的癖好,它喜欢把汉犇犇一个叠一个的放置. 因为它有强迫症,所以每当它想放一个新的汉犇犇进去的时候并不一定想直接叠在最上面,简单的说,当他想放第 ...