## $>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的更多相关文章

  1. Topcoder Srm 673 Div2 1000 BearPermutations2

    \(>Topcoder \space Srm \space 673 \space Div2 \space 1000 \space BearPermutations2<\) 题目大意 : 对 ...

  2. TopCoder SRM 660 Div2 Problem 1000 Powerit (积性函数)

    令$f(x) = x^{2^{k}-1}$,我们可以在$O(k)$的时间内求出$f(x)$. 如果对$1$到$n$都跑一遍这个求解过程,时间复杂度$O(kn)$,在规定时间内无法通过. 所以需要优化. ...

  3. TopCoder SRM 301 Div2 Problem 1000 CorrectingParenthesization(区间DP)

    题意  给定一个长度为偶数的字符串.这个字符串由三种括号组成. 现在要把这个字符串修改为一个符合括号完全匹配的字符串,改变一个括号的代价为$1$,求最小总代价. 区间DP.令$dp[i][j]$为把子 ...

  4. SRM 146 DIV2 1000

    Problem Statement      A well-known riddle goes like this: Four people are crossing an old bridge. T ...

  5. 求拓扑排序的数量,例题 topcoder srm 654 div2 500

    周赛时遇到的一道比较有意思的题目: Problem Statement      There are N rooms in Maki's new house. The rooms are number ...

  6. Topcoder srm 632 div2

    脑洞太大,简单东西就是想复杂,活该一直DIV2; A:水,基本判断A[I]<=A[I-1],ANS++; B:不知道别人怎么做的,我的是100*N*N;没办法想的太多了,忘记是连续的数列 我们枚 ...

  7. topcoder SRM 628 DIV2 BracketExpressions

    先用dfs搜索所有的情况,然后判断每种情况是不是括号匹配 #include <vector> #include <string> #include <list> # ...

  8. topcoder SRM 628 DIV2 BishopMove

    题目比较简单. 注意看测试用例2,给的提示 Please note that this is the largest possible return value: whenever there is ...

  9. Topcoder SRM 683 Div2 B

    贪心的题,从左向右推过去即可 #include <vector> #include <list> #include <map> #include <set&g ...

随机推荐

  1. UIControl事件---iOS-Apple苹果官方文档翻译

    本系列所有开发文档翻译链接地址: iOS7开发-Apple苹果iPhone开发Xcode官方文档翻译PDF下载地址 UIControl事件1.UIControlEventTouchDown单点触摸按下 ...

  2. 超详细的Java面试题总结(二)之Java基础知识篇

    多线程和Java虚拟机 创建线程有几种不同的方式?你喜欢哪一种?为什么? 继承Thread类 实现Runnable接口 应用程序可以使用Executor框架来创建线程池 实现Callable接口. 我 ...

  3. Java案例之随机验证码功能实现

    实现的功能比较简单,就是随机产生了四个字符然后输出.效果图如下,下面我会详细说一下实现这个功能用到了那些知识点,并且会把 这些知识点详细的介绍出来.哈哈 ,大神勿喷,对于初学Java的人帮助应该蛮大的 ...

  4. perl6文件操作

    use v6; #perl6中读取文件方法 #:r 只读, :w 只写, :rw 读写, :a 追加 my $fp = open 'filename.txt', :rw; for $fp.^metho ...

  5. url编码模块

    use LWP::SImple; use URI::Escape; encoded_string = uri_escape(raw_string); get(encoded_string);

  6. vue基本介绍

    https://cn.vuejs.org/v2/guide/ Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架.与其它大型框架不同的是,Vue 被设计为可以自底向上 ...

  7. linux===启动sdk manager下载配置sdk的时候报错的解决办法

    当启动sdk manager下载配置sdk的时候,报错如下: botoo@botoo-virtual-machine:/opt/android-sdk-linux/tools$ sudo  ./and ...

  8. python基础=== itertools介绍(转载)

    原文链接:http://python.jobbole.com/85321/ Python提供了一个非常棒的模块用于创建自定义的迭代器,这个模块就是 itertools.itertools 提供的工具相 ...

  9. Centos_Lvm expand capacity without restarting CentOS

    Rescan the new disk(/dev/sdb): #ls /sys/class/scsi_host/ host0 host1 host2 [root@db210_13:56:14 /dat ...

  10. 坐标转换——GCJ-02

    WGS84(World Geodetic System 1984),是为GPS 全球定位系统 使用而建立的坐标系统GCJ-02,我国在WGS84的基础上加密得到BD-09,百度坐标在GCJ-02基础上 ...