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->20,表示这个格子连接上下。
02->00,表示这个格子作为某个地板的终点。
10->01,表示这个格子连接左右。
10->20,表示在这个格子作为中间的拐角。
11->00,表示这个格子作为结束的拐角。
20->00,表示这个格子作为某个地板的终点。
20->02,表示这个格子连接左右。
(插头DP的本质就是分类讨论,所以麻烦也没办法,想明白就很容易了)
然后就是实现了。我是用unordered_map存储状态,同时先找到第一个可以放东西的位置开始DP,统计答案的时候统计第n+1行没有插头的状态。

代码:

 1 #pragma GCC optimize(2)
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<tr1/unordered_map>
 5 using namespace std;
 6 using namespace tr1;
 7 const int maxn=1e2+1e2;
 8 const int mod=20110520;
 9
10 int sta[maxn],nxt[maxn];
11 char in[maxn][maxn]; // in == 1 means empty .
12 int n,m,cur,fx,fy;
13 unordered_map<int,int> f[2];
14
15 inline void unzip(int* sta,int ss) {
16     for(int i=m+1;i;i--) sta[i] = ss % 3 , ss /= 3;
17 }
18 inline int zip(int* sta) {
19     int ret = 0;
20     for(int i=1;i<=m+1;i++) ret = ret * 3 + sta[i];
21     return ret;
22 }
23
24 inline void core_trans(unordered_map<int,int> &dst,int x,int y,int add) {
25     memcpy(nxt,sta,sizeof(int)*(m+2));
26     if( !in[x][y] ) { // not empty .
27         if( sta[y] == 0 && sta[y+1] == 0 ) ( dst[zip(nxt)] += add ) %= mod;
28         return;
29     }
30     if( sta[y] == 0 ) {
31         if( sta[y+1] == 0 ) {
32             nxt[y] = 2 , nxt[y+1] = 2 , ( dst[zip(nxt)] += add ) %= mod;
33             nxt[y] = 1 , nxt[y+1] = 0 , ( dst[zip(nxt)] += add ) %= mod;
34             nxt[y] = 0 , nxt[y+1] = 1 , ( dst[zip(nxt)] += add ) %= mod;
35         } else if( sta[y+1] == 1 ) {
36             nxt[y] = 1 , nxt[y+1] = 0 , ( dst[zip(nxt)] += add ) %= mod;
37             nxt[y] = 0 , nxt[y+1] = 2 , ( dst[zip(nxt)] += add ) %= mod;
38         } else if( sta[y+1] == 2 ) {
39             nxt[y] = 2 , nxt[y+1] = 0 , ( dst[zip(nxt)] += add ) %= mod;
40             nxt[y] = 0 , nxt[y+1] = 0 , ( dst[zip(nxt)] += add ) %= mod;
41         }
42     } else if( sta[y] == 1 ) {
43         if( sta[y+1] == 0 ) {
44             nxt[y] = 0 , nxt[y+1] = 1 , ( dst[zip(nxt)] += add ) %= mod;
45             nxt[y] = 2 , nxt[y+1] = 0 , ( dst[zip(nxt)] += add ) %= mod;
46         } else if( sta[y+1] == 1 ) nxt[y] = 0 , nxt[y+1] = 0 , ( dst[zip(nxt)] += add ) %= mod;
47     } else if( sta[y] == 2 ) {
48         if( sta[y+1] == 0 ) {
49             nxt[y] = 0 , nxt[y+1] = 0 , ( dst[zip(nxt)] += add ) %= mod;
50             nxt[y] = 0 , nxt[y+1] = 2 , ( dst[zip(nxt)] += add ) %= mod;
51         }
52     }
53 }
54 inline void trans(const unordered_map<int,int> &sou,unordered_map<int,int> &dst,int x,int y) {
55     dst.clear();
56     for(unordered_map<int,int>::const_iterator it=sou.begin();it!=sou.end();it++) if( it->second ) {
57         unzip(sta,it->first) , core_trans(dst,x,y,it->second);
58     }
59 }
60 inline void transline(const unordered_map<int,int> &sou,unordered_map<int,int> &dst) {
61     dst.clear();
62     for(unordered_map<int,int>::const_iterator it=sou.begin();it!=sou.end();it++) if( it->second && ! ( it->first % 3 ) ) {
63         dst[it->first/3] = it->second;
64     }
65 }
66
67 inline void revert() { // make m <= n .
68     static char tp[maxn][maxn];
69     memcpy(tp,in,sizeof(in)) , memset(in,0,sizeof(in));
70     for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) in[j][i] = tp[i][j];
71     swap(n,m);
72 }
73
74 int main() {
75     scanf("%d%d",&n,&m) , fx = -1 , fy = -1;
76     for(int i=1;i<=n;i++) {
77         scanf("%s",in[i]+1);
78         for(int j=1;j<=m;j++) in[i][j] = in[i][j] == ‘_‘;
79     }
80
81     if( n < m ) revert();
82     for(int i=1;i<=n&&!~fx;i++) for(int j=1;j<=m&&!~fx;j++) if(in[i][j]) fx = i , fy = j;
83     if( !~fx ) return puts("1") , 0; // nothing to do .
84     sta[fy] = 0 , sta[fy+1] = 1 , f[cur][zip(sta)] = 1;
85     sta[fy] = 1 , sta[fy+1] = 0 , f[cur][zip(sta)] = 1;
86     sta[fy] = sta[fy+1] = 2 , f[cur][zip(sta)] = 1;
87     for(int j=fy+1;j<=m;j++) trans(f[cur],f[cur^1],fx,j) , cur ^= 1;
88     transline(f[cur],f[cur^1]) , cur ^= 1;
89
90     for(int i=fx+1;i<=n;i++) {
91         for(int j=1;j<=m;j++)
92             trans(f[cur],f[cur^1],i,j) , cur ^= 1;
93         transline(f[cur],f[cur^1]) , cur ^= 1;
94     }
95
96     printf("%d\n",f[cur][0]);
97
98     return 0;
99 }

たいせつなきみのために ぼくにできるいちばんのことは
为了最重要的你 我所能做的最好的事
約束を忘れること君への想い消し去ること
就是忘却与你的约定抹去对你的思念
沈む夕日暮れてく空 夜の帳舞い降りる頃
渐渐归隐大地的夕阳 夜幕降临整个天空 夜的气息轻盈飘落之时
僕は目を閉じて それは闇に溶けるように 滲んで消えた
我闭目去感受 一切就像溶入暗影一样 渗透进去消散无痕了

未来なんていらないよ
未来(明日)什么的已经不需要了吧
君が側にいる過去のままで
因为有你一直陪伴我的往昔(昨日)

原文地址:https://www.cnblogs.com/Cmd2001/p/9043222.html

时间: 2024-10-12 03:10:30

2331: [SCOI2011]地板 插头DP的相关文章

【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

bzoj 2331: [SCOI2011]地板 插头dp

用四进制表示状态. 用hash表把一个四进制数映射到一个小数上. 这样就可以memset了. 转移的时候分类讨论一下,特判下边界情况. 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdio> 5 #define bq 1<<bit[j] 6 #define bp 1<<bit[j-1] 7 using namespace std

【BZOJ2331】[SCOI2011]地板 插头DP

[BZOJ2331][SCOI2011]地板 Description lxhgww的小名叫“小L”,这是因为他总是很喜欢L型的东西.小L家的客厅是一个的矩形,现在他想用L型的地板来铺满整个客厅,客厅里有些位置有柱子,不能铺地板.现在小L想知道,用L型的地板铺满整个客厅有多少种不同的方案? 需要注意的是,如下图所示,L型地板的两端长度可以任意变化,但不能长度为0.铺设完成后,客厅里面所有没有柱子的地方都必须铺上地板,但同一个地方不能被铺多次. Input 输入的第一行包含两个整数,R和C,表示客厅

【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型的地板铺满整个客厅有多少种不同的方案? 需要注意的是,如下图所示,

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

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

bzoj2331 : [SCOI2011]地板 2011-12-20

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

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时可以转移

P3272 [SCOI2011]地板(插头DP)

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

BZOJ2331:[SCOI2011]地板——题解

http://www.lydsy.com/JudgeOnline/problem.php?id=2331 题面复制于洛谷 题目描述 lxhgww的小名叫”小L“,这是因为他总是很喜欢L型的东西.小L家的客厅是一个R*C的矩形,现在他想用L型的地板来铺满整个客厅,客厅里有些位置有柱子,不能铺地板.现在小L想知道,用L型的地板铺满整个客厅有多少种不同的方案?需要注意的是,如下图所示,L型地板的两端长度可以任意变化,但不能长度为0. 铺设完成后,客厅里面所有没有柱子的地方都必须铺上地板,但同一个地方不