【插头DP】 BZOJ 2331 地板

通道:http://www.lydsy.com/JudgeOnline/problem.php?id=2331

题意:用L型的填满格子,有障碍。

思路:0表示该格无插头,1表示向内,2表示向外。

  (1)如果left插头和up插头都为0

     1.从未决策右边和下边格子引两条箭头

     2.从该格向未决策的右边引外插头

     3.从该格向未决策的下边引外插头

  (2)如果left插头或者up插头为0,如果有拐角,则按原方向转移。

(3)如果left插头和up插头均为1,状态合法

代码:

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4
  5 using namespace std;
  6
  7 const int MAX_N = 103;
  8 const int MAX_M = 103;
  9 const int HASH = 100007;
 10 const int MAX_S = 1000007;
 11 const int MOD = 20110520;
 12
 13 const int mov[20] = {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30};
 14
 15 struct node {
 16     int head[HASH], nxt[MAX_S], cnt;
 17     long long dp[MAX_S], st[MAX_S];
 18     void init() {
 19         memset(head, -1, sizeof head);
 20         cnt = 0;
 21     }
 22     void push(long long s, long long v) {
 23         int now = s % HASH;
 24         for(int i = head[now]; ~i; i = nxt[i]) if(st[i] == s) {
 25             dp[i] = (dp[i] + v) % MOD;
 26             return ;
 27         }
 28         st[cnt] = s;      dp[cnt] = v;
 29         nxt[cnt] = head[now];
 30         head[now] = cnt++;
 31     }
 32 }d[2];
 33
 34 int n, m;
 35 int ex, ey;
 36
 37 int find_pos(long long s, int p) {
 38     return s >> mov[p] & 3;
 39 }
 40
 41 void tp(long long &s, int p, long long v) {
 42     s &= ~(3ll << mov[p]);
 43     s |= v << mov[p];
 44 }
 45
 46
 47 int find_r(long long s, int p) {
 48     int cnt = 0;
 49     for(int i = p; i <= m; ++i) {
 50         if(find_pos(s, i) == 1) ++cnt;
 51         else if(find_pos(s, i) == 2) --cnt;
 52         if(!cnt) return i;
 53     }
 54 }
 55
 56 int find_l(long long s, int p) {
 57     int cnt = 0;
 58     for(int i = p; i >= 0; --i) {
 59         if(find_pos(s, i) == 2) ++cnt;
 60         else if(find_pos(s, i) == 1) --cnt;
 61         if(!cnt) return i;
 62     }
 63 }
 64 long long ans1;
 65
 66 void blank(int i, int j, int cur) {
 67     for(int k = 0; k < d[cur].cnt; ++k) {
 68         long long t = d[cur].st[k];
 69         int l = find_pos(t, j - 1), r = find_pos(t, j);
 70         if(l && r) {
 71             if(l == 1 && r == 1) {
 72                 tp(t, j - 1, 0); tp(t, j, 0);
 73                 d[cur ^ 1].push(t, d[cur].dp[k]);
 74                 if (i == ex && j == ey) ans1 = (ans1 + d[cur].dp[k]) % MOD;
 75             }
 76         } else if(l) {
 77             if(i < n && l == 1) {
 78                 tp(t, j - 1, 2); tp(t, j, 0);
 79                 d[cur ^ 1].push(t, d[cur].dp[k]);
 80             }
 81             if(j < m) {
 82                 t = d[cur].st[k];
 83                 tp(t, j - 1, 0); tp(t, j, l);
 84                 d[cur ^ 1].push(t, d[cur].dp[k]);
 85             }
 86             if(l == 2) {
 87                 t = d[cur].st[k];
 88                 tp(t, j - 1, 0); tp(t, j, 0);
 89                 d[cur ^ 1].push(t, d[cur].dp[k]);
 90                 if (i == ex && j == ey) ans1 = (ans1 + d[cur].dp[k]) % MOD;
 91             }
 92         } else if(r) {
 93             if(j < m && r == 1) {
 94                 tp(t, j - 1, 0); tp(t, j, 2);
 95                 d[cur ^ 1].push(t, d[cur].dp[k]);
 96             }
 97             if(i < n) {
 98                 t = d[cur].st[k];
 99                 tp(t, j - 1, r); tp(t, j, 0);
100                 d[cur ^ 1].push(t, d[cur].dp[k]);
101             }
102             if(r == 2) {
103                 t = d[cur].st[k];
104                 tp(t, j - 1, 0); tp(t, j, 0);
105                 d[cur ^ 1].push(t, d[cur].dp[k]);
106                 if (i == ex && j == ey) ans1 = (ans1 + d[cur].dp[k]) % MOD;
107             }
108
109
110         } else { // 新建
111             if(i < n && j < m) {
112                 tp(t, j - 1, 2); tp(t, j, 2);
113                 d[cur ^ 1].push(t, d[cur].dp[k]);
114             }
115             if (i < n) {
116                 t = d[cur].st[k];
117                 tp(t, j - 1, 1); tp(t, j, 0);
118                 d[cur ^ 1].push(t, d[cur].dp[k]);
119             }
120             if (j < m) {
121                 t = d[cur].st[k];
122                 tp(t, j - 1, 0); tp(t, j, 1);
123                 d[cur ^ 1].push(t, d[cur].dp[k]);
124             }
125         }
126     }
127 }
128
129 void block(int i, int j, int cur) {
130     for (int k = 0; k < d[cur].cnt; ++k) {
131         long long t = d[cur].st[k];
132         int l = find_pos(t, j - 1), r = find_pos(t, j);
133         if (!l && !r) d[cur ^ 1].push(t, d[cur].dp[k]);
134     }
135 }
136
137 char str[107];
138 int a[MAX_N][MAX_M], z[MAX_N][MAX_M];
139
140 int main() {
141     while (2 == scanf("%d%d", &n, &m)) {
142         memset(a, 0, sizeof a);
143         for (int i = 1; i <= n; ++i) {
144             scanf("%s", str + 1);
145             for (int j = 1; j <= m; ++j) {
146                 if (str[j] == ‘_‘) {
147                     a[i][j] = 1;
148                     ex = i, ey = j;
149                 }
150             }
151         }
152            if (n < m) {
153                for (int i = 1; i <= n; ++i)
154                    for (int j = 1; j <= m; ++j)
155                        z[j][i] = a[i][j];
156                swap(ex, ey); swap(n, m);
157                memcpy(a, z, sizeof z);
158            }
159            int cur = 0;
160         d[cur].init();
161         d[cur].push(0, 1);
162         ans1 = 0;
163         for (int i = 1; i <= n; ++i) {
164             for (int j = 1; j <= m; ++j) {
165                 d[cur ^ 1].init();
166                 if (a[i][j]) blank(i, j, cur);
167                 else block(i, j, cur);
168                 cur ^= 1;
169             }
170             for (int j = 0; j < d[cur].cnt; ++j)
171                 d[cur].st[j] <<= 2;
172         }
173         ans1 %= MOD;
174         printf("%d\n", ans1);
175     }
176     return 0;
177 }

时间: 2024-08-01 22:36:56

【插头DP】 BZOJ 2331 地板的相关文章

BZOJ 2331 地板(插头DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2331 题意:给出一个n*m的地面.有些是障碍.用L型的地板砖铺满.有多少种方案. 思路:用0表示没有插头,用1表示有插头且可以拐弯,用3表示有插头但是不能再拐弯了. 设有m列,轮廓线为[0,m].对于格子(i,j),设左插头x上插头y,那么转移有: (1)x=0,y=0:此时如图1-0,有三种转移,分别是1-1,1-2,1-3; (2)x!=0,y!=0:此时只有当x=y=1时可以转移

【BZOJ】2331: [SCOI2011]地板 插头DP

[题意]给定n*m的地板,有一些障碍格,要求用L型的方块不重不漏填满的方案数.L型方块是从一个方格向任意两个相邻方向延伸的方块,不能不延伸.n*m<=100. [算法]插头DP [题解]状态0表示无插头,1表示能拐弯的插头,2表示不能拐弯的插头.(有插头,方块就必须必须延伸到该格),考虑转移即可. 注意可以凭空产生一个能拐弯的插头. n*m<=100,当m>10的时候将i,j互换. #include<cstdio> #include<cstring> #inclu

2331: [SCOI2011]地板 插头DP

国际惯例的题面:十分显然的插头DP.由于R*C<=100,所以min(R,C)<=10,然后就可以愉悦地状压啦.我们用三进制状压,0表示没有插头,1表示有一个必须延伸至少一格且拐弯的插头,2表示有一个必须延伸一格且不可以拐弯的插头.转移的话就十分显然了.00->22,表示用这个格子作为开始的拐角.00->10,表示用这个格子向下延伸.00->01,表示用这个格子向右延伸.01->10,表示这个格子连接上下.01->02,表示在这个格子作为中间的拐角.02->

【BZOJ 2331】 [SCOI2011]地板

2331: [SCOI2011]地板 Time Limit: 5 Sec  Memory Limit: 128 MB Submit: 598  Solved: 264 [Submit][Status][Discuss] Description lxhgww的小名叫"小L",这是因为他总是很喜欢L型的东西.小L家的客厅是一个的矩形,现在他想用L型的地板来铺满整个客厅,客厅里有些位置有柱子,不能铺地板.现在小L想知道,用L型的地板铺满整个客厅有多少种不同的方案? 需要注意的是,如下图所示,

BZOJ 2595 游览计划(插头DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2595 题意:给出一个数字矩阵.求一个连通块包含所有的数字0且连通块内所有数字之和最小. 思路:对于每个格子,是0则必须要选.那么对于不选的格子(i,j)在什么时候可以不选呢?必须同时满足以下两个条件: (1)(i,j)不是0: (2)(i-1,j)不选或者(i-1,j)选了但是轮廓线上还有别的地方与(i-1,j)是一个连通块. int Pre[105][N],op[105][N]; s

bzoj 1187: [HNOI2007]神奇游乐园 插头dp

1187: [HNOI2007]神奇游乐园 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 668  Solved: 337[Submit][Status][Discuss] Description 经 历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细一看,才发现这是一个游 乐场,专为旅途中疲惫的人设计.娱乐场可以看成是一块大小为n×m的区域,且这个n×m的区域被分成n×m个

【题解】互不侵犯 SCOI 2005 BZOJ 1087 插头dp

以前没学插头dp的时候觉得这题贼难,根本不会做,学了才发现原来是一裸题. 用二进制表示以前的格子的状态,0表示没放国王,1表示放了国王. 假设当前位置为(x,y),需要记录的是(x-1,y-1)至(x,y-1)的信息,共n+1个点. 每个状态有两种决策,第一种是这个格子不放国王,直接转移. 第二种是这个格子放国王,需要满足几个条件才能进行这步转移,条件很显然,具体见代码和注释. 因为状态数很少,所以也用不到BFS转移状态和Hash的技巧,所以这题还是很清真的,细节不多,码量也很小. #inclu

P3272 [SCOI2011]地板(插头DP)

[题面链接] https://www.luogu.org/problemnew/show/P3272 [题目描述] 有一个矩阵,有些点必须放,有些点不能放,用一些L型的图形放满,求方案数 [题解] (版权所有) https://www.luogu.org/blog/dedicatus545/solution-p3272 第一种情况:当前状态下,当前格子上方和左方都没有插头 这时我们需要找一个L形来把这个格子填上,那么我们可能有三种决策: 决策一:给这个格子加一个二号下插头和一个二号右插头,此时这

[入门向选讲] 插头DP:从零概念到入门 (例题:HDU1693 COGS1283 BZOJ2310 BZOJ2331)

转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/7326874.html 最近搞了一下插头DP的基础知识……这真的是一种很锻炼人的题型…… 每一道题的状态都不一样,并且有不少的分类讨论,让插头DP十分锻炼思维的全面性和严谨性. 下面我们一起来学习插头DP的内容吧! 插头DP主要用来处理一系列基于连通性状态压缩的动态规划问题,处理的具体问题有很多种,并且一般数据规模较小. 由于棋盘有很特殊的结构,使得它可以与“连通性”有很强的联系,因此插头DP最常见的应用要数