洛谷 P4815 [CCO2014] 狼人游戏

首先题目中有 3 3 3 个限制:

  • 没有机器人又被指控又被保护;
  • 没有机器人被指控或保护一次以上;
  • 如果有一个编号为 A A A 机器人指控或保护编号为 B B B 的机器人,那么我们保证 A < B A<B A<B。

那么我们把每一个机器人看成一个节点,每一个关系看成一条对应的边,由指控或保护者指向被指控或被保护者,那么结合前两个限制,容易发现,每一个点的入度只能为 0 0 0 或者 1 1 1,第三个限制保证了整个图没有环。那么整张图就变成了一个森林。

设 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k] 表示以 i i i 为根的子树,有 j j j 个狼人的方案数,其中 k = 0 k=0 k=0 表示节点 i i i 不是狼人, k = 1 k=1 k=1 表示节点 i i i 是狼人。那么一共只有 6 6 6 种对应的父子关系。

指控:

  • 狼人父亲指控市民儿子
  • 市民父亲指控市民儿子
  • 市民父亲指控狼人儿子

保护:

  • 狼人父亲保护狼人儿子
  • 市民父亲保护市民儿子
  • 市民父亲保护狼人儿子

这样的话我们可以列出转移方程,设 u u u 为父亲, v v v 为儿子。

当这条边是指控边时:
f [ u ] [ j ] [ 1 ] = f [ u ] [ j − k ] [ 1 ] × f [ v ] [ k ] [ 0 ] f[u][j][1] = f[u][j-k][1] \times f[v][k][0] f[u][j][1]=f[u][j−k][1]×f[v][k][0] f [ u ] [ j ] [ 0 ] = f [ u ] [ j − k ] [ 0 ] × ( f [ v ] [ k ] [ 0 ] + f [ v ] [ k ] [ 1 ] ) f[u][j][0] = f[u][j-k][0] \times (f[v][k][0] + f[v][k][1]) f[u][j][0]=f[u][j−k][0]×(f[v][k][0]+f[v][k][1])

当这条边是保护边时:
f [ u ] [ j ] [ 1 ] = f [ u ] [ j − k ] [ 1 ] × f [ v ] [ k ] [ 1 ] f[u][j][1] = f[u][j-k][1] \times f[v][k][1] f[u][j][1]=f[u][j−k][1]×f[v][k][1] f [ u ] [ j ] [ 0 ] = f [ u ] [ j − k ] [ 0 ] × ( f [ v ] [ k ] [ 0 ] + f [ v ] [ k ] [ 1 ] ) f[u][j][0] = f[u][j-k][0] \times (f[v][k][0] + f[v][k][1]) f[u][j][0]=f[u][j−k][0]×(f[v][k][0]+f[v][k][1])

接下来考虑如何处理森林。我们可以新建一个超级源点 0 0 0,连向所有的树根,然后我们最终的答案直接在超级源点上处理即可,即为 f [ 0 ] [ w ] [ 0 ] f[0][w][0] f[0][w][0]。

我们需要注意,在树形 DP 转移的时候,我们需要用一个变量来代替前面的 f [ u ] [ j ] [ 0 ] f[u][j][0] f[u][j][0] 和 f [ u ] [ j ] [ 1 ] f[u][j][1] f[u][j][1] 来进行转移,在后面把 f [ u ] [ j ] [ 0 ] f[u][j][0] f[u][j][0] 和 f [ u ] [ j ] [ 1 ] f[u][j][1] f[u][j][1] 给赋值,因为在转移的过程中,我们要保证 f [ u ] [ j ] [ 0 ] f[u][j][0] f[u][j][0] 和 f [ u ] [ j ] [ 1 ] f[u][j][1] f[u][j][1] 的值不能被实时更新,在转移的时候需要用到原来的 f [ u ] [ j ] [ 0 ] f[u][j][0] f[u][j][0] 和 f [ u ] [ j ] [ 1 ] f[u][j][1] f[u][j][1]。

#include <bits/stdc++.h>
#define re register
#define ll long long
#define rep(a,b,c)  for(re int a(b) ; a<=c ; ++a)
#define drep(a,b,c) for(re int a(b) ; a>=c ; --a)
using namespace std;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48) ; ch=getchar();}return x*f;
}
const int M = 210;
const int mod = 1e9+7;
int n,s,m,cnt;
int head[M],siz[M],son[M],du[M];
ll f[M][M][2]; //0 市民 1 狼人
struct edge{int to,nxt,w; //w=1 指控 w=2 保护
}e[M<<1];
inline void add(int u,int v,int w){e[++cnt].to = v;e[cnt].w = w;e[cnt].nxt = head[u];head[u] = cnt;
}
void dfs(int u){siz[u] = 1;f[u][0][0] = f[u][1][1] = 1;for(re int i(head[u]) ; i ; i=e[i].nxt){int v = e[i].to,w = e[i].w;dfs(v);siz[u] += siz[v];drep(j,min(s,siz[u]),0){int dp0 = 0,dp1 = 0;rep(k,0,min(j,siz[v])){if(w == 1){dp0 += f[u][j-k][0] * (f[v][k][0] + f[v][k][1]) % mod;dp1 += f[u][j-k][1] * f[v][k][0] % mod;dp0 %= mod,dp1 %= mod;}else{dp0 += f[u][j-k][0] * (f[v][k][0] + f[v][k][1]) % mod;dp1 += f[u][j-k][1] * f[v][k][1] % mod;dp0 %= mod,dp1 %= mod;}}f[u][j][0] = dp0;f[u][j][1] = dp1;}}
}
signed main(){n = read(),s = read(),m = read();rep(i,1,m){char ch;cin >> ch;int u = read(),v = read();if(ch == 'D') add(u,v,2);else add(u,v,1);du[v]++;}rep(i,1,n) if(!du[i]) add(0,i,1);dfs(0);printf("%lld\n",f[0][s][0]);return 0;
}

洛谷 P4815 狼人游戏 题解相关推荐

  1. NOIP 提高组 2012 / 洛谷P1080 国王游戏 题解

    题面: 略 简易题解: 假设第iii位大臣左手为LiL_{i}Li​, 右手的数为R_{i} 并且我们有两位大臣iii,jjj,考虑他们的相对位置 (PPP 是 iii , jjj 之前的左手数值累乘 ...

  2. 洛谷P1057传球游戏题解--zhengjun

    题目描述 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做传球游戏. 游戏规则是这样的: n n n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传 ...

  3. 洛谷 P2670扫雷游戏 题解

    题目描述 扫雷游戏是一款十分经典的单机小游戏.在nn行mm列的雷区中有一些格子含有地雷(称之为地雷格),其他格子不含地雷(称之为非地雷格).玩家翻开一个非地雷格时,该格将会出现一个数字--提示周围格子 ...

  4. 洛谷P2670扫雷游戏题解

    题目 这道题是一个简单的模拟搜索题,可以把每个雷的位置都记作1. 这样就可记录出数字啦 #include<iostream> #include<cstring> using n ...

  5. 洛谷P1057传球游戏题解

    题目 这个题表面上看并不像DP,但是当我们看到方案数时,我们可能会想到什么??? 对,分类加法原理,在每一轮中,每一个点的方案数都要加上这个点左边的方案与右边的方案. 因此我们可以枚举,设一个DP数组 ...

  6. 洛谷P1070道路游戏题解--zhengjun

    题面传送门 思路 首先,这道题一定是个dpdpdp,因为题中说一旦机器人走到头了,就要立刻在其他任意的一个机器人工厂买. 一开始弄得fi,jf_{i,j}fi,j​是到了第iii个工厂,用了jjj个时 ...

  7. 洛谷P4099 [HEOI2013]SAO 题解

    洛谷P4099 [HEOI2013]SAO 题解 题目链接:P4099 [HEOI2013]SAO 题意: Welcome to SAO ( Strange and Abnormal Online). ...

  8. 洛谷P2507 [SCOI2008]配对 题解(dp+贪心)

    洛谷P2507 [SCOI2008]配对 题解(dp+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1299251 链接题目地址:洛谷P2507 [S ...

  9. 洛谷P2312 解方程题解

    洛谷P2312 解方程题解 题目描述 已知多项式方程: \[a_0+a_1x+a_2x^2+\cdots+a_nx^n=0\] 求这个方程在 \([1,m]\) 内的整数解(\(n\) 和 \(m\) ...

最新文章

  1. JavaScript setTimeout() 介绍
  2. Exchange Server 2013 DAG高可用部署(四)-服务器配置(上)
  3. Ubuntu12.04 安装 mongodb
  4. virtualbox虚拟机ubuntu和宿主机xp文件件共享方法
  5. 马斯克采访:要么死的安然,要么活得绚烂
  6. linux 内存清理 释放命令,Linux系统中的内存清理和释放命令总结
  7. P3480-[POI2009]KAM-Pebbles【阶梯博弈】
  8. 【队列】Team Queue(luogu-UVA540/poj 2259)
  9. html内置时间对象,JavaScript中的常用事件,以及内置对象详解
  10. Linux开机启动过程(4):切换到64位模式-长模式(直到内核解压缩之前)
  11. (二)使用预定义模型 QStringListModel例子
  12. 接口自动化持续集成实战
  13. mysql与其他数据库的区别_mysql与其他数据库的区别
  14. JavaWeb中的问题 ---- Servlet和Jsp
  15. Matrix Cookbook 公式推导
  16. 计算机永远无法超越人类——从李世石与阿尔法的人机大战中想到的
  17. table 表格边框线去重
  18. 谈一下wxid转扫一扫的核心
  19. VR开发之使用VRTK实现拾取和手柄扣下扳机触发事件(Unity灭火器灭火功能的实现)
  20. PAT 甲级 1108 Finding Average (20 分)

热门文章

  1. 入门Linux系统编程--网络编程
  2. 为了联盟还是为了部落 | K means
  3. 网络安全意识 | 线上社交竟潜藏如此恶魔...
  4. c# mysql 连接串_C#数据库连接字符串
  5. python loads_Python中的dump() 和load()以及dumps()和loads()
  6. python语言第11天笔记
  7. 计算机制作灯笼,电脑怎么做灯笼
  8. x264代码剖析(七):encode()函数之x264_encoder_encode()函数
  9. 扫地机器人对地面的压强_送给打工人的经验帖:为了省心省力的搞定地板清洁,扫地机器人该如何选择?...
  10. 手机进程设置多少个最好_vivo手机这3个设置没关?难怪手机总卡顿耗电,关了手机流畅如新...