Topcoder Srm 671 Div2 1000 BearDestroysDiv2
## $>Topcoder \space Srm \space 671 \space Div2 \space 1000 \space BearDestroysDiv2
题目大意 : 有一个 \(W \times H\) 的网格,每一格上有一棵树和一个随机字母 \(S\) 或 \(E\) ,有一只熊在左上角,按从上到下从左到右的顺序遍历每一行每一列,如果其遇到一棵可以推倒的树,就尽可能按照字母表示的方向 (向下,向右) 推倒它,然后其推倒方向的下一棵树就不能被推倒了,同时树不能被推倒在边界之外,求对于所有可能的网格图,树的被推倒个数总和对 \(Mod\) 取模的值 。
\(1 \leq W \leq 7 \ ,1 \leq H \leq 40\)
解题思路 :
观察到 \(W\) 比较小,不妨对列进行状态压缩,又因为直接状压每一列后效性很难讨论,所以维护轮廓线来 \(dp\) 转移.
设 \(f[i][r][j][s]\) 表示第 \(i\) 行维护的轮廓线断点在 \(r\), 轮廓线上的点的状态为 \(s\) ,到目前位置推倒了 \(j\) 棵树的答案
考虑直接将轮廓线上的点定义为 {没推倒,向\(E\)推倒,向\(S\)推倒} 三种不仅无法很好描述状态来转移,复杂度也差强人意
观察发现,对于轮廓线上的点转移到下一状态时,被推倒和因为其他树推倒在它身上导致不能推倒是等价的.
换一种说法,轮廓线上的点对后面状态的更新当且仅当取决于其在此刻能否被推倒,不妨用 \(0\) 表示可以被推倒 \(1\)表示不行

如图所示,绿色的是当前的轮廓线,红色的是要被更新的轮廓线,当前要把点 \(P_2\) 加到轮廓线中.
如果 \(mask(P_0) = 0\) 说明 \(P_0\) 能推倒但因为一些原因没有推倒其右边的点,根据题意,此时 \(P_0\) 必须要向下推倒
考虑 \(P_0\) 被向下推倒了之后,\(P_1\) 就不能向右推倒了,所以 \(P_1\) 如果要向下推倒选 \(S, E\) 都可以.
\(P_2\) 因为被卡住了不能动,所以选 \(S, E\) 也都可以,所以转移的时候方案数的系数为 \(2 \times \max(2 \times [mask(P_1) = 0], 1)\)
如果 \(mask(P_0) = 1\) 且 \(maxk(P_1) = 0\)
此时 \(P_1\) 既可以向下推倒又可以向右推倒,向下的情况只需要保留当且轮廓线的状态即可
考虑 \(P_1\) 要向右推倒,当且仅当 \(P_0\) 没有向下推倒且 \(P_1\) 上的字母为 \(E\) , 所以转移的时候方案数的系数为 \(2\)
如果都不能推倒,那么只需要保留当前轮廓线状态并添加新的点 \(P_2\) 即可
考虑边界的情况,对于所有右边界和下边界,推倒的树的字母都可以选择两种
特别的,对于下边界上的点,\(P_1\) 只能选择向右推倒,对于最后状态产生的未推倒的树,都可以选取两种颜色
所以只需要枚举轮廓线和推倒的树的个数,分类讨论转移
此题细节比较多,建议多算几遍系数,复杂度是 \(O(\frac{W^2H}{2}\times2^W)\)
/*program by mangoyang*/
typedef long long ll;
ll f[45][10][176][1<<7], Mod;
inline void update(ll &x, ll y){ (x += y) %= Mod; }
int BearDestroysDiv2::sumUp(int W, int H, int MOD){
memset(f, 0, sizeof(f));
int all = W * H / 2 + 1, lim = (1 << W) - 1;
f[0][W][0][lim] = 1, Mod = MOD;
for(int i = 1; i <= H; i++){
for(int j = 0; j <= all; j++)
for(int s = 0; s <= lim; s++) f[i][0][j][s] = f[i-1][W][j][s];
for(int r = 0; r < W; r++)
for(int j = 0; j <= all; j++)
for(int s = 0; s <= lim; s++){
if(!((1 << r) & s)){
ll s2 = (r == W - 1) ? 2 : 1, s1 = 1;
if(r && !((1 << r - 1) & s) && i != H) s1 = 2;
update(f[i][r+1][j+1][s|(1<<r)], f[i][r][j][s] * 2 * s2 * s1);
}
else{
if(i < H) update(f[i][r+1][j][s^(1<<r)], f[i][r][j][s]);
if(r && !((1 << r - 1) & s)){
ll s2 = (i == H) ? 2 : 1;
update(f[i][r+1][j+1][s|(1<<r)|(1<<r-1)], f[i][r][j][s] * 2 * s2);
}
else if(i == H) update(f[i][r+1][j][s^(1<<r)], f[i][r][j][s]);
}
}
}
ll ans = 0;
for(int j = 1; j <= all; j++)
for(int s = 0; s <= lim; s++) if(f[H][W][j][s]){
ll res = 1;
for(int i = 0; i < W; i++)
if(!((1 << i) & s)) res *= 2;
update(ans, f[H][W][j][s] * j * res);
}
return ans;
}
Topcoder Srm 671 Div2 1000 BearDestroysDiv2的更多相关文章
- Topcoder Srm 673 Div2 1000 BearPermutations2
\(>Topcoder \space Srm \space 673 \space Div2 \space 1000 \space BearPermutations2<\) 题目大意 : 对 ...
- TopCoder SRM 660 Div2 Problem 1000 Powerit (积性函数)
令$f(x) = x^{2^{k}-1}$,我们可以在$O(k)$的时间内求出$f(x)$. 如果对$1$到$n$都跑一遍这个求解过程,时间复杂度$O(kn)$,在规定时间内无法通过. 所以需要优化. ...
- TopCoder SRM 301 Div2 Problem 1000 CorrectingParenthesization(区间DP)
题意 给定一个长度为偶数的字符串.这个字符串由三种括号组成. 现在要把这个字符串修改为一个符合括号完全匹配的字符串,改变一个括号的代价为$1$,求最小总代价. 区间DP.令$dp[i][j]$为把子 ...
- SRM 146 DIV2 1000
Problem Statement A well-known riddle goes like this: Four people are crossing an old bridge. T ...
- 求拓扑排序的数量,例题 topcoder srm 654 div2 500
周赛时遇到的一道比较有意思的题目: Problem Statement There are N rooms in Maki's new house. The rooms are number ...
- Topcoder srm 632 div2
脑洞太大,简单东西就是想复杂,活该一直DIV2; A:水,基本判断A[I]<=A[I-1],ANS++; B:不知道别人怎么做的,我的是100*N*N;没办法想的太多了,忘记是连续的数列 我们枚 ...
- topcoder SRM 628 DIV2 BracketExpressions
先用dfs搜索所有的情况,然后判断每种情况是不是括号匹配 #include <vector> #include <string> #include <list> # ...
- topcoder SRM 628 DIV2 BishopMove
题目比较简单. 注意看测试用例2,给的提示 Please note that this is the largest possible return value: whenever there is ...
- Topcoder SRM 683 Div2 B
贪心的题,从左向右推过去即可 #include <vector> #include <list> #include <map> #include <set&g ...
随机推荐
- Winform Socket通信
Socket相关概念[端口] 在Internet上有很多这样的主机,这些主机一般运行了多个服务软件,同时提供几种服务.每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应 ...
- 【Python学习】matplotlib的颜色
matplotlib自带的颜色 seaborn的颜色 装了seaborn扩展的话,在字典seaborn.xkcd_rgb中包含所有的xkcd crowdsourced color names. 使用的 ...
- Caffe学习笔记4图像特征进行可视化
Caffe学习笔记4图像特征进行可视化 本文为原创作品,未经本人同意,禁止转载,禁止用于商业用途!本人对博客使用拥有最终解释权 欢迎关注我的博客:http://blog.csdn.net/hit201 ...
- linux编程之多线程编程
我们知道,进程在各自独立的地址空间中运行,进程之间共享数据需要用mmap或者进程间通信机制,有些情况需要在一个进程中同时执行多个控制流程,这时候线程就派上了用场,比如实现一个图形界面的下载软件,一方面 ...
- Linux线程同步
1. 线程同步: 当多个控制线程共享相同的内存时,需要确保每个线程看到一致的数据视图.当某个线程可以修改变量,而其他线程也可以读取或者修改这个变量的时候,就需要对这些线程进行同步,以确保他们在访问变量 ...
- python基础===autopep8__python代码规范
关于PEP 8 PEP 8,Style Guide for Python Code,是Python官方推出编码约定,主要是为了保证 Python 编码的风格一致,提高代码的可读性. 官网地址:http ...
- 移动端测试===安卓设备共享程序-发布版本“share device”
分享一个开源的项目 share device 项目地址:https://github.com/sunshine4me/ShareDevicePublish/tree/win7-x64 首先选择对应系统 ...
- PhysX SDK
PhysX SDK https://developer.nvidia.com/physx-sdk NVIDIA PhysX SDK Downloads http://www.nvidia.cn/obj ...
- problems when installed mysql in linux ubuntu
reference:http://www.jb51.net/article/87160.htm?pc 1.ERROR 2002 (HY000): Can't connect to local MySQ ...
- jQuery 选中tr下面的第某个td
1.问题描述 点击 table 中的某行 tr,获取该 tr 下的第一个 td 标签下的< input type="hidden" value="92"/ ...