点此看题面

大致题意: 已知有平民和狼人共\(n\)个,每个平民会指控和保护任何人,每个狼人只会指控平民、保护狼人。告诉你\(m\)对指控与保护的关系,求有\(k\)个狼人的方案总数。

树形\(DP\)

这题目乍看很神仙,但一看给出的其他一些限制,就可以发现这就是一棵树!

而对于这种问题,容易想到用树形\(DP\)去求解。

我们可以设\(f_{i,0/1,j,0/1}\)来表示编号为\(i\)的节点作为平民/狼人时共有\(j\)个狼人的方案数,其中第二维分别表示上一次和这一次的答案,用了滚存

则显然可以推得\(DP\)方程如下:

\[f_{x,op,j+l,0}=\sum f_{x,op\text{^}1,j,0}*(f_{son,sz_{son}\&1,l,0}+f_{son,sz_{son}\&1,l,0})
\]

\[f_{x,op,j+l,1}=\sum f_{x,op\text{^}1,j,1}*f_{son,sz_{son}\&1,l,[val=='D']}
\]

对于第一个方程,我们知道平民会指控和保护任何人,因此无论子节点为平民还是狼人都可以转移。

对于第二个方程,我们知道狼人只会指控平民、保护狼人,因此当指控关系时子节点必须为平民,当保护关系时子节点必须为狼人。

统计答案

由于这是一片森林,因此我们最后还需要统计答案,而这也是一个类似的过程。

我们可以设\(s_{0/1,j}\)来表示共有\(j\)个狼人的方案数,其中第一维类似于前面的第二位,分别表示上一次和这一次的答案。

若我们从\(0\)号节点向所有根节点连边,则转移式其实是几乎一样的:

\[s_{op,j+l}=\sum s_{op\text{^}1,j}*(f_{son,sz_{son}\&1,l,0}+f_{son,sz_{son}\&1,l,0})
\]

其实很好理解,这与上面的式子就少了枚举当前节点是平民还是狼人,而\(0\)号节点作为虚拟节点,显然都不是嘛。。。

具体实现详见代码。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<tepename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define RC Reg char
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 200
#define X 1000000007
#define min(x,y) ((x)>(y)?(x):(y))
#define add(x,y,v) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].op=v)
#define Inc(x,y) ((x+=(y))>=X&&(x-=X))
using namespace std;
int n,m,k,ee,deg[N+5],lnk[N+5];struct edge {int to,nxt;char op;}e[N+5];
I int XSum(RI x,CI y) {return x+y>=X?x+y-X:x+y;}
class TreeDper//树形DP
{
private:
int s[2][N+5],t[N+5],g[N+5],f[N+5][2][N+5][2];
I void DP(CI x)//DP
{
g[x]=f[x][0][0][0]=f[x][0][1][1]=1;for(RI i=lnk[x],j,l,op=1;i;i=e[i].nxt,op^=1)//初始化信息,枚举子节点
{
for(memset(f[x][op],0,sizeof(f[x][op])),DP(e[i].to),j=min(k,g[x]);~j;--j) for(l=min(k-j,g[e[i].to]);~l;--l)//枚举状态进行转移
{
Inc(f[x][op][j+l][0],1LL*f[x][op^1][j][0]*XSum(f[e[i].to][t[e[i].to]][l][0],f[e[i].to][t[e[i].to]][l][1])%X),
Inc(f[x][op][j+l][1],1LL*f[x][op^1][j][1]*f[e[i].to][t[e[i].to]][l][e[i].op=='D']%X);
}g[x]+=g[e[i].to],t[x]^=1;//更新size
}
}
public:
I int GetAns()//与上面的过程类似
{
RI i,j,l,op=1;for(s[0][0]=1,i=lnk[0];i;i=e[i].nxt,op^=1)
for(memset(s[op],0,sizeof(s[op])),DP(e[i].to),j=k;~j;--j) for(l=min(k-j,g[e[i].to]);~l;--l)
Inc(s[op][j+l],1LL*s[op^1][j]*XSum(f[e[i].to][t[e[i].to]][l][0],f[e[i].to][t[e[i].to]][l][1])%X);
return s[op^1][k];
}
}T;
int main()
{
ios::sync_with_stdio(false);
RI i,x,y,ans=1;RC op;for(cin>>n>>k>>m,i=1;i<=m;++i) cin>>op>>x>>y,add(x,y,op),++deg[y];//读入+建边
for(i=1;i<=n;++i) !deg[i]&&add(0,i,'*');return printf("%d",T.GetAns()),0;//求解并输出
}

【洛谷4815】[CCO2014] 狼人游戏(树形DP)的更多相关文章

  1. 洛谷 P3177 [HAOI2015]树上染色 树形DP

    洛谷 P3177 [HAOI2015]树上染色 树形DP 题目描述 有一棵点数为 \(n\) 的树,树边有边权.给你一个在 \(0 \sim n\)之内的正整数 \(k\) ,你要在这棵树中选择 \( ...

  2. 洛谷 P4201 设计路线 [NOI2008] 树形dp

    正解:树形dp 解题报告: 大概是第一道NOI的题目?有点激动嘻嘻 然后先放个传送门 先大概港下这题的题意是啥qwq 大概就是给一棵树,然后可以选若干条链把链上的所有边的边权变成0,但是这些链不能有交 ...

  3. 洛谷P1040 加分二叉树(树形dp)

    加分二叉树 时间限制: 1 Sec  内存限制: 125 MB提交: 11  解决: 7 题目描述 设一个n个节点的二叉树tree的中序遍历为(l,2,3,...,n),其中数字1,2,3,...,n ...

  4. 洛谷P4438 道路 [HNOI/AHOI2018] 树形dp

    正解:树形dp 解题报告: 传送门! 昂首先看懂题目趴QwQ大概就是说有棵满二叉树,有n个叶子节点(乡村)和n-1个非叶子节点,然后这棵树的每个节点有三个属性abc,对每个非叶子节点可以从与子节点的两 ...

  5. 洛谷 P3267 [JLOI2016/SHOI2016]侦察守卫(树形dp)

    题面 luogu 题解 树形\(dp\) \(f[x][y]表示x的y层以下的所有点都已经覆盖完,还需要覆盖上面的y层的最小代价.\) \(g[x][y]表示x子树中所有点都已经覆盖完,并且x还能向上 ...

  6. 洛谷P1351 联合权值(树形dp)

    题意 题目链接 Sol 一道很简单的树形dp,然而被我写的这么长 分别记录下距离为\(1/2\)的点数,权值和,最大值.以及相邻儿子之间的贡献. 树形dp一波.. #include<bits/s ...

  7. 洛谷P4099 [HEOI2013]SAO(树形dp)

    传送门 HEOI的题好珂怕啊(各种意义上) 然后考虑树形dp,以大于为例 设$f[i][j]$表示$i$这个节点在子树中排名第$j$位时的总方案数(因为实际只与相对大小有关,与实际数值无关) 我们考虑 ...

  8. 洛谷 P1351 联合权值 —— 树形DP

    题目:https://www.luogu.org/problemnew/show/P1351 树形DP,别忘了子树之间的情况(拐一下距离为2). 代码如下: #include<iostream& ...

  9. 洛谷 P2634 聪聪可可 —— 树形DP / 点分治

    题目:https://www.luogu.org/problemnew/show/P2634 今天刚学了点分治,做例题: 好不容易A了,结果发现自己写的是树形DP...(也不用找重心)(比点分治快) ...

  10. 洛谷P3047 [USACO12FEB]Nearby Cows(树形dp)

    P3047 [USACO12FEB]附近的牛Nearby Cows 题目描述 Farmer John has noticed that his cows often move between near ...

随机推荐

  1. Linux用户登录信息

    1.用户登录日志信息 /var/run/utmp:记录当前正在登录系统的用户信息,默认由who和w记录当前登录用户的信息,uptime记录系统启动时间: /var/log/wtmp:记录当前正在登录和 ...

  2. HDFS读写文件流程

    读取: 写入:https://www.imooc.com/article/70527

  3. Maven 错误 Failure to transfer ...was cached in the local repository...

    Maven 错误 Failure to transfer ...was cached in the local repository... 我解决的时候多了两步才解决 1. mvn clean ins ...

  4. sql 中单引号内嵌套单引号该怎么解决

    # 在mybatis 中写过一个比较少见的sql, 单引号呢需要嵌套一个单引号,使用双引号就会报错,怎么解决呢: * 这个时候可以使用两个单引号,eg : select id from pgr_dij ...

  5. 17965 幸运之星(优先做) 约瑟夫环问题O(n)

    17965 幸运之星(优先做) 时间限制:100MS  内存限制:65535K 提交次数:0 通过次数:0 题型: 编程题   语言: G++;GCC;VC Description 每年新年派对的最后 ...

  6. AJAX重点知识的心得体会

    下面就为大家带来一篇 AJAX重点知识的心得体会.学习还是有点帮助的,给大家做个参考吧. AJAX是什么? 是Asynchronous Javascript And XML的首字母的缩写, 它不是一门 ...

  7. SQL Server 创建用户

    增加角色 role_for_nc 1.exec sp_addrole 'role_for_nc'; 创建一个 SQL Server 登录名wlzx,密码为"123",默认数据库为 ...

  8. DataColumn.Expression提示“...循环引用”的错误

    我碰到这个问题的时候,在网上找了找,找到了有好几个提出这个问题的人,但是都没有得到解答,当时很郁闷.然后再看看msdn中的解释与自己的测试,才把这个问题给解决了. 代码如下: person.Colum ...

  9. MySQL GROUP_CONCAT长度限制引发的一场灾难

    GROUP_CONCAT函数是对查处的分组数据对于分组列相同的数据合并成一列用逗号隔开的函数. 但是该函数的长度有个默认限制,默认是1024个字符,超过就会截断,从而导致用count统计GROUP_C ...

  10. Gremlin--一种支持对图表操作的语言

    Gremlin 是操作图表的一个非常有用的图灵完备的编程语言.它是一种Java DSL语言,对图表进行查询.分析和操作时使用了大量的XPath. Gremlin可用于创建多关系图表.因为图表.顶点和边 ...