点此看题面

大致题意: 已知有平民和狼人共\(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. AnnotationConfigApplicationContext

    package com.test; import java.io.IOException; import java.io.InputStream; import java.net.URL; impor ...

  2. 逐行创建、读取并写入txt(matlab) && 生成文件夹里文件名的.bat文件

    fidin=fopen('C:\Users\byte\Desktop\新建文件夹 (4)\tr4.txt','r'); fidout=fopen('C:\Users\byte\Desktop\新建文件 ...

  3. 二分搜索 - Binary Search

    二分搜索是一种在有序数组中寻找目标值的经典方法,也就是说使用前提是『有序数组』.非常简单的题中『有序』特征非常明显,但更多时候可能需要我们自己去构造『有序数组』.下面我们从最基本的二分搜索开始逐步深入 ...

  4. 使用hive数据仓库中遇到的问题

    1. 原因:hive版本过高.我用的是3.1.1最高版本,所以报此错.

  5. ExtJS 开发总结

    1. ExtJS的定位是RIA,和Prototype.jQuery等类库的定位不同.使用ExtJS做开发,就是意味着以客户端开发为主,不然就不叫RIA框架了,而Prototype.jQuery等只是辅 ...

  6. java 与 数据库的连接

    Eclipse中使用SQL server 2017数据库 一.准备材料 要能够使用数据库就要有相应的JDBC,所以我们要去Microsoft官网下载https://www.microsoft.com/ ...

  7. javascript 例外处理Try{}catch(e){}

    程序开发中,编程人员经常要面对的是如何编写代码来响应错误事件的发生,即例外处理(exception handlers).如果例外处理代码设计得周全,那么最终呈现给用户的就将是一个友好的界面.否则,就会 ...

  8. leetcode 182. Duplicate Emails having的用法 SQL执行顺序

    https://leetcode.com/problems/duplicate-emails/description/ 首先sql的执行顺序是 from-->where-->group b ...

  9. 性能测试工具LoadRunner20-LR之Controller Service-Level Agreement(服务水平协议)

    SLA是为负载测试场景定义的具体目标.例如,评测脚本中任意数量事务的平均响应时间,可以定义具体的目标或阈值.测试运行结束之后,LR将你定义的目标与实际录制的平均事务响应时间进行比较.如果实际的平均事务 ...

  10. linux下Python2.7编译安装PyQt5

    ---作者吴疆,未经允许,严禁转载,违权必究--- ---欢迎指正,需要源码和文件可站内私信联系--- -----------点击此处链接至博客园原文----------- 功能说明:在ubuntu系 ...