BZOJ 2331 SCOI 2011 地板 插头DP
来源:互联网 发布:游戏推广系统源码 编辑:程序博客网 时间:2024/04/29 08:55
求用L形方块占满有障碍棋盘的方案数。
对于每个插头,定义状态有:
- 0 - 无插头
- 1 - 入插头:指向L的拐点的称为入。
- 2 - 出插头:相对地。
那么,就可以分情况讨论了。下面以左、上以及下、右的顺序描述插头。
- 均无插头
- 无和入或入和出(即L的一个端点)
- 均为出(即L的拐点)
- 均有插头
- 均为出(即L的拐点,合并两插头)
- 其余情况均不合法。
- 只有一个有插头
- 左为出:延续(下无右出)或停止(下右无)
- 左为入:延续(下无右入)或拐弯(下出右无)
- 上的情况类似。
注意到每个状态都可能扩展出很多状态,实际状态数会爆炸。
发现如果上层跑完一次的轮廓线,最右边不为无插头的状态显然是不合法的,剔除,然后就神奇地A了。。。
不过讲道理拿到以前的题目一点变化都没有。。。。
#include <cstdio>#include <algorithm>#include <cstring>#include <map>#define rep(i,j,k) for(i=j;i<k;i++)using namespace std;const int mod = 20110520;const int state[] = {0, -1, 1, 0};int get_bit(int sta, int i) { return (sta >> (i << 1)) & 3; }int set_bit(int &sta, int i, int x) { sta = (sta & ~(3 << (i << 1))) | (x << (i << 1));}const int HASH_STORAGE = 2000000, HASH_SIZE = 100007;struct HashMap { int key[HASH_STORAGE], val[HASH_STORAGE]; int head[HASH_SIZE], next[HASH_STORAGE], sz; void clear() { sz = 0; memset(head, -1, sizeof head); } void add(int k, int v) { int t = k % HASH_SIZE; for (int i = head[t]; i != -1; i = next[i]) if (key[i] == k) { (val[i] += v) %= mod; return; } key[sz] = k; val[sz] = v; next[sz] = head[t]; head[t] = sz++; }} h[2], *cur, *last;char mp[101][101], MP[101][101];int bx, by, n, m;void update(int x, int y, int sta, int v) { int l = get_bit(sta, y), s; int t = get_bit(sta, y + 1); #define create(i,j) s=sta,set_bit(s,y,i),set_bit(s,y+1,j),cur->add(s,v) if (mp[x][y] == '*') { if (!l && !t) create(0, 0); return; } if (!l && !t) { create(0, 1); create(1, 0); create(2, 2); } else if (!l || !t) { if (l == 2) create(0, 0), create(0, 2); else if (l == 1) create(0, 1), create(2, 0); if (t == 2) create(0, 0), create(2, 0); else if (t == 1) create(1, 0), create(0, 2); } else if (l == 1 && t == 1) create(0, 0);}int solve() { int i, j, k; cur = h; last = h + 1; last->clear(); last->add(0,1); rep(i,0,n) { int rate = 2; rep(j,0,m) { cur->clear(); rep(k,0,last->sz) { if (rate == 2 && get_bit(last->key[k], m)) continue; update(i, j, last->key[k] << rate, last->val[k]); } rate = 0; swap(cur, last); } } int ans = 0; rep(k,0,last->sz) if (last->key[k] == 0) { ans = last->val[k]; break; } return ans;}int main() { int i, j; scanf("%d%d", &n, &m); rep(i,0,n) scanf("%s", mp[i]); if (m > n) { rep(j,0,m) rep(i,0,n) MP[j][i] = mp[i][j]; swap(n, m); rep(i,0,n) rep(j,0,m) mp[i][j] = MP[i][j]; } bx = by = -1; for(i=n-1;i>=0;--i) for(j=m-1;j>=0;--j) if (mp[i][j] == '_') bx = i, by = j, i = -1, j = -1; printf("%d", solve()); return 0;}
2331: [SCOI2011]地板
Time Limit: 5 Sec Memory Limit: 128 MB
Submit: 827 Solved: 350
[Submit][Status][Discuss]
Description
lxhgww的小名叫“小L”,这是因为他总是很喜欢L型的东西。小L家的客厅是一个的矩形,现在他想用L型的地板来铺满整个客厅,客厅里有些位置有柱子,不能铺地板。现在小L想知道,用L型的地板铺满整个客厅有多少种不同的方案?
需要注意的是,如下图所示,L型地板的两端长度可以任意变化,但不能长度为0。铺设完成后,客厅里面所有没有柱子的地方都必须铺上地板,但同一个地方不能被铺多次。
Input
输入的第一行包含两个整数,R和C,表示客厅的大小。
接着是R行,每行C个字符。’_’表示对应的位置是空的,必须铺地板;’*’表示对应的位置有柱子,不能铺地板。
Output
输出一行,包含一个整数,表示铺满整个客厅的方案数。由于这个数可能很大,只需输出它除以20110520的余数。
Sample Input
2 2*___
Sample Output
1
HINT
Source
Day1
0 0
- BZOJ 2331 SCOI 2011 地板 插头DP
- BZOJ 2331 SCOI2011 地板 插头DP
- [BZOJ]2331: [SCOI2011]地板 插头DP
- 【bzoj2331】[SCOI2011]地板 插头dp
- Bzoj2331[SCOI2011]地板:插头dp
- [插头DP] BZOJ2331 && SCOI2011 地板
- 【BZOJ 2331】 [SCOI2011]地板
- BZOJ 2331 [SCOI2011]地板
- [BZOJ]3125: CITY 插头DP
- [BZOJ]3125: CITY 插头DP
- [BZOJ]2310: ParkII 插头DP
- [BZOJ 1068][SCOI 2007]压缩(DP)
- [BZOJ 1090][SCOI 2003]字符串折叠(DP)
- 【dp】【bzoj 1079】【SCOI 2008】着色方案
- BZOJ 1087 SCOI 互不侵犯 状态DP
- 【BZOJ 1068】【SCOI 2007】压缩 【区间DP】
- [BZOJ 1025] SCOI 2009 游戏 · DP
- BZOJ 1084 [SCOI 2005] DP 解题报告
- POJ 1182 - 食物链
- 尝试读jquery源码_1
- 原地逆置列表reverseList
- 面试常客Handler详细解析(主线程与子线程信息交互)(五)
- 反转链表
- BZOJ 2331 SCOI 2011 地板 插头DP
- C++封装学习(一)
- UICollectionView的高级使用和上拉加载下拉刷新
- maven、java 内存泄漏与spring Ioc DI
- TCP组包问题及处理方法
- android中Translate动画
- JQuery之ajax
- AJAX - 创建 XMLHttpRequest 对象
- UESTC--1251(模拟)