bzoj2331 [SCOI2011]地板
2331: [SCOI2011]地板
Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 1427 Solved: 601
[Submit][Status][Discuss]
Description
lxhgww的小名叫“小L”,这是因为他总是很喜欢L型的东西。小L家的客厅是一个R*C的矩形,现在他想用L型的地板来铺满整个客厅,客厅里有些位置有柱子,不能铺地板。现在小L想知道,用L型的地板铺满整个客厅有多少种不同的方案?
需要注意的是,如下图所示,L型地板的两端长度可以任意变化,但不能长度为0。铺设完成后,客厅里面所有没有柱子的地方都必须铺上地板,但同一个地方不能被铺多次。
Input
输入的第一行包含两个整数,R和C,表示客厅的大小。
接着是R行,每行C个字符。’_’表示对应的位置是空的,必须铺地板;’*’表示对应的位置有柱子,不能铺地板。
Output
输出一行,包含一个整数,表示铺满整个客厅的方案数。由于这个数可能很大,只需输出它除以20110520的余数。
Sample Input
*_
__
Sample Output
HINT
R*C<=100
Source
分析:非常神奇的一道题.
这道题很容易看出来用插头dp做. 但是如果用左括号右括号表示插头这道题做不了,没办法转移.
题目限制了L两端的长度不能为0,说明L一定存在一个拐点. 可以用插头表示L. 如果状态为0,则表示不存在插头;如果状态为1,则表示插头目前是一条直线;如果状态为2,则表示插头已经拐了一个弯,是一个L形了.
考虑怎么转移. 假设当前枚举到的点是(i,j),令(i-1,j)的右插头为p,(i,j - 1)的下插头为q,(i,j)的下插头为p',(i,j)的右插头为q',分以下几种合法的情况:
1.p = q = 0,那么可以转移到3个状态:p' = 1,q' = 0; p' = 0,q' = 1; p' = q' = 2. 三者的含义很容易看出来.前两个是引出一条线段,最后一个是引出一条折线段“L形”.
2.p = 0,q = 1. 这种情况下q可以继续往下走,状态不变,p' = 1,q' = 0. 也可以往右拐,状态变成2, p' = 0,q' = 2.
3.p = 1,q = 0,和第二种情况类似.
4.p = 0,q = 2. 有两种选择,要么就在此停下,路径结束. 如果在最后一个非障碍点停下就可以统计答案了. 要么继续走,不能拐弯,这个时候p' = 2,q' = 0.
5.p = 2,q = 0,和第四种情况类似.
6.p = q = 1.两个插头结合在一起形成了一个L形,(i,j)不存在右插头和下插头,那么p' = q' = 0.
最后统计答案找状态等于0的.
两个坑点:1.maxn要开大! 2.n * m ≤ 100,如果m偏大要交换n,m.
这道题挺好的,插头不仅可以表示左右括号,它作为维护连通性的工具,还可以被赋予别的意义,前提是要能够转移.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int mod = 20110520,maxn = 1000010; int n,m,a[110][110],now,pre,pow[110],tx,ty; char s[110]; struct node { int head[maxn],nextt[maxn],sum[maxn],sta[maxn],tot; void clear() { memset(head,-1,sizeof(head)); tot = 0; memset(sum,0,sizeof(sum)); memset(sta,0,sizeof(sta)); } void push(int x,int v) { int hashh = x % 50000; for (int i = head[hashh]; i >= 0; i = nextt[i]) { if (sta[i] == x) { sum[i] = (sum[i] + v) % mod; return; } } sum[tot] = v; sta[tot] = x; nextt[tot] = head[hashh]; head[hashh] = tot++; } } f[2]; int turnleft(int x,int pos) { return x << pow[pos]; } int get(int x,int pos) { return (x >> pow[pos]) & 3; } int del(int x,int i,int j) { return x & (~(3 << pow[i])) & (~(3 << pow[j])); } void solve2(int x,int y,int k) { int p = get(f[pre].sta[k],y - 1); int q = get(f[pre].sta[k],y); int staa = del(f[pre].sta[k],y - 1,y); int v = f[pre].sum[k]; if (!p && !q) { if (a[x][y] == 0) { f[now].push(staa,v); return; } if (x < n && a[x + 1][y] == 1) f[now].push(staa | turnleft(1,y - 1),v); if (y < m && a[x][y + 1] == 1) f[now].push(staa | turnleft(1,y),v); if (x < n && a[x + 1][y] == 1 && y < m && a[x][y + 1] == 1) f[now].push(staa | turnleft(2,y) | turnleft(2,y - 1),v); } else if (p == 0 && q == 1) { if (x < n && a[x + 1][y] == 1) f[now].push(staa | turnleft(1,y - 1),v); if (y < m && a[x][y + 1] == 1) f[now].push(staa | turnleft(2,y),v); } else if (q == 0 && p == 1) { if (x < n && a[x + 1][y] == 1) f[now].push(staa | turnleft(2,y - 1),v); if (y < m && a[x][y + 1] == 1) f[now].push(staa | turnleft(1,y),v); } else if (p == 1 && q == 1) f[now].push(staa,v); else if (p == 0 && q == 2) { f[now].push(staa,v); if (x < n && a[x + 1][y] == 1) f[now].push(staa | turnleft(2,y - 1),v); } else if (p == 2 && q == 0) { f[now].push(staa,v); if (y < m && a[x][y + 1] == 1) f[now].push(staa | turnleft(2,y),v); } } int solve() { now = 0,pre = 1; f[0].clear(); f[0].push(0,1); for (int i = 1; i <= n; i++) { pre = now; now ^= 1; f[now].clear(); for (int k = 0; k < f[pre].tot; k++) f[now].push(turnleft(f[pre].sta[k],1),f[pre].sum[k]); for (int j = 1; j <= m; j++) { pre = now; now ^= 1; f[now].clear(); for (int k = 0; k < f[pre].tot; k++) solve2(i,j,k); } } for (int i = 0; i < f[now].tot; i++) if (f[now].sta[i] == 0) return f[now].sum[i]; return 0; } int main() { freopen("test.txt","r",stdin); for (int i = 1; i <= 100; i++) pow[i] = i * 2; scanf("%d%d",&n,&m); if (n >= m) { for (int i = 1; i <= n; i++) { scanf("%s",s + 1); for (int j = 1; j <= m; j++) { if (s[j] == '_') a[i][j] = 1; else a[i][j] = 0; } } } else { for (int i = 1; i <= n; i++) { scanf("%s",s + 1); for (int j = 1; j <= m; j++) { if (s[j] == '_') a[j][i] = 1; else a[j][i] = 0; } } swap(n,m); } printf("%d\n",solve() % mod); return 0; }