题解

把所有=的点连起来,一个图合法肯定它是一个有向树森林

我们新建一个点,把这个点和其他所有树的树根连起来

定义\(dp[u][j]\)表示第u个点长度为j的序列的方案数

转移方法是

\(dp[u][j] += g[k] \cdot dp[v][h] \cdot \binom{j}{k} \cdot \binom{k}{h - j + k}\)

\(g[k]\)是我们记录之前儿子合并的序列为k的方案数

就是我们确定目标序列的长度为\(j\)后,选\(k\)个位置放第一个序列,在这\(k\)个位置中再选\(h - j + k\)个作为第二个序列和第一个序列重合的部分,和之前的空位一起放第二个序列

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 105
//#define ivorysi
using namespace std;
typedef long long int64;
typedef long double db;
typedef unsigned int u32;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {putchar('-');x = -x;}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
const int MOD = 1000000007;
int N,M,id[MAXN],cnt;
int u[MAXN],v[MAXN],f[MAXN],ind[MAXN];
char ch[MAXN][5];
int vis[MAXN],C[MAXN][MAXN],dp[MAXN][MAXN],siz[MAXN],g[MAXN],s[MAXN];
struct node {
int next,to;
}E[MAXN * 2];
int sumE,head[MAXN];
int inc(int a,int b) {
return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
return 1LL * a * b % MOD;
}
void add(int u,int v) {
E[++sumE].next = head[u];
E[sumE].to = v;
head[u] = sumE;
}
int getf(int u) {
return f[u] == u ? u : f[u] = getf(f[u]);
}
bool check(int u) {
vis[u] = 1;
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(!vis[v]) {if(!check(v)) return false;}
if(vis[v] == 1) return false;
}
vis[u] = 2;
return true;
}
void Init() {
read(N);read(M);
for(int i = 1 ; i <= N ; ++i) f[i] = i;
for(int i = 1 ; i <= M ; ++i) {
read(u[i]);scanf("%s",ch[i]);read(v[i]);
if(ch[i][0] == '=') {
f[getf(u[i])] = getf(v[i]);
}
}
for(int i = 1 ; i <= N ; ++i) {
if(!id[getf(i)]) id[getf(i)] = ++cnt;
}
for(int i = 1 ; i <= M ; ++i) {
if(ch[i][0] == '<') {
add(id[getf(u[i])],id[getf(v[i])]);
ind[id[getf(v[i])]]++;
}
}
N = cnt + 1;
for(int i = 1 ; i <= cnt ; ++i) if(!ind[i]) add(N,i);
C[0][0] = 1;
for(int i = 1 ; i <= 101 ; ++i) {
C[i][0] = 1;
for(int j = 1 ; j <= i ; ++j) {
C[i][j] = inc(C[i - 1][j],C[i - 1][j - 1]);
}
}
}
void dfs(int u) {
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
dfs(v);
}
memset(g,0,sizeof(g));
g[0] = 1;
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
for(int j = 0 ; j <= siz[u] + siz[v] ; ++j) {
s[j] = 0;
for(int k = 0 ; k <= siz[v] ; ++k) {
if(k > j) break;
for(int h = 0 ; h <= siz[u] ; ++h) {
if(h > j) break;
s[j] = inc(s[j],mul(mul(dp[v][k],g[h]),mul(C[j][k],C[k][h - j + k])));
}
}
}
for(int j = 0 ; j <= siz[u] + siz[v] ; ++j) g[j] = s[j];
siz[u] += siz[v];
}
++siz[u];
for(int j = 1 ; j <= siz[u] ; ++j) dp[u][j] = g[j - 1];
}
void Solve() {
for(int i = 1 ; i <= N ; ++i) {
if(!vis[i] && !check(i)) {puts("0");return;}
}
dfs(N);
int ans = 0;
for(int i = 0 ; i <= N ; ++i) ans = inc(ans,dp[N][i]);
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
return 0;
}

【LOJ】#2117. 「HNOI2015」实验比较的更多相关文章

  1. loj #2116. 「HNOI2015」开店

    #2116. 「HNOI2015」开店 题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的想法当然非 ...

  2. Loj #2192. 「SHOI2014」概率充电器

    Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  3. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

  4. Loj #3093. 「BJOI2019」光线

    Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...

  5. Loj #3089. 「BJOI2019」奥术神杖

    Loj #3089. 「BJOI2019」奥术神杖 题目描述 Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的 ...

  6. Loj #2542. 「PKUWC2018」随机游走

    Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...

  7. Loj #3059. 「HNOI2019」序列

    Loj #3059. 「HNOI2019」序列 给定一个长度为 \(n\) 的序列 \(A_1, \ldots , A_n\),以及 \(m\) 个操作,每个操作将一个 \(A_i\) 修改为 \(k ...

  8. Loj #3056. 「HNOI2019」多边形

    Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...

  9. LOJ #2135. 「ZJOI2015」幻想乡战略游戏(点分树)

    题意 给你一颗 \(n\) 个点的树,每个点的度数不超过 \(20\) ,有 \(q\) 次修改点权的操作. 需要动态维护带权重心,也就是找到一个点 \(v\) 使得 \(\displaystyle ...

随机推荐

  1. Mac 删除应用卸载后无法正常移除的图标

    经常会不通过appstore下载软件,也就是从网页中下载dmg,自己安装,但是当我不再想要这个软件,然后把它卸载掉之后就会发现,launchpad里还是遗留了这个软件的图标,而且删不掉.这个时候,就可 ...

  2. ssm controller层 junit单元测试

    原文链接:https://www.cnblogs.com/oucbl/p/5943743.html springmvc controller junit 测试 作者:blouc@qq.com本文为作者 ...

  3. Qt ------ UDP发送不了或接收不到问题

    1.禁用不需要的网卡,比如禁用虚拟机网卡. 2.向所有网卡广播数据 /* * 直接调用 QUdpSocket 的 writeDatagram() 函数发送数据,如果有多张网卡(装了虚拟机会增加网卡), ...

  4. Hadoop生态圈-Flume的主流Channel源配置

    Hadoop生态圈-Flume的主流Channel源配置 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   一. 二. 三.

  5. spring boot 分布式事务实现(XA方式)

    关于spring boot 支持分布式事务,XA是常用的一种方式. 这里把相关的配置记下,方便以后使用. 首先配置两个不同的数据源 : 订单库.持仓库. /** * Created by zhangj ...

  6. Windows环境下Qwt安装和使用

    之前安装过,现在记录下关键步骤,方便后面使用和复习吧. 环境:win10   Qt5.9  Qt Creator 4.3 参考:https://blog.csdn.net/linuxarmsummar ...

  7. log4j2常见配置

    依赖jar: <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId> ...

  8. np.linespace使用方法

    np.linespace用法 觉得有用的话,欢迎一起讨论相互学习~Follow Me 生成指定范围内指定个数的一维数组 def linspace(start, stop, num=50, endpoi ...

  9. shell test条件判断

    test 条件判断 # 符号 [ ] 等同  test命令 test -lt # 判断大小 echo $? # 查看上句test命令返回状态 # 结果0为真,1为假 test -n "hel ...

  10. 04 uni-app框架学习:禁用顶部原生导航栏

    1.在pages.json中配置 比如要首页禁用 就在首页这个选项里 加上这几句代码 2.效果如下