P3272 [SCOI2011]地板(插头DP)
[题面链接] https://www.luogu.org/problemnew/show/P3272
[题目描述] 有一个矩阵,有些点必须放,有些点不能放,用一些L型的图形放满,求方案数
[题解] (版权所有) https://www.luogu.org/blog/dedicatus545/solution-p3272
第一种情况:当前状态下,当前格子上方和左方都没有插头
这时我们需要找一个L形来把这个格子填上,那么我们可能有三种决策:
决策一:给这个格子加一个二号下插头和一个二号右插头,此时这个格子是一个新的L形的拐角
决策二:给这个格子加一个一号下插头,此时相当于构建了一个先向下再向右的L形,从当前格子开始
决策三:给这个格子加一个一号右插头,此时相当于构建了一个先向右再向下的L形,从当前格子开始
第二种情况:当前状态下,当前格子上方有一个一号下插头,左方没有插头
这时相当于上面有一个L形的未拐弯的一边伸过来了,有两种决策:
决策一:L形不拐弯,继续向下延伸,当前格子只有一个一号下插头
决策二:L形在当前格子拐弯,L形向右延伸,当前格子只有一个二号右插头
第三种情况:当前状态下,当前格子左方有一个一号右插头,上方没有插头
与第二种情况类似,故不赘述
第四种情况:当前状态下,当前格子上方有一个二号下插头,左方没有插头
这时相当于上面有一个L形的拐过弯的一边伸过来了,有两种决策:
决策一:L形继续延伸,当前格子有一个二号下插头
决策二:L形在当前格子终止,当前格子没有插头
决策二时注意,如果当前处在最后一个没有障碍的格子,那么需要统计入最终答案
第五种情况:当前状态下,当前格子左方有一个二号右插头,上方没有插头
与第四种情况类似,故不赘述
第六种情况:当前状态下,当前格子左方和上方都有一号插头
此时相当于两条“臂”伸了过来,在当前格子相交,应该合并成一个L形
当前格子相当于一个L形的拐弯处,没有插头
我们发现,情况一和情况六已经覆盖了四种L形的摆放方式,同时也不会有一个二号插头一个一号插头或者两个二号插头的情况出现——它们被上文的六种情况限制了
故这种分类讨论方式可以覆盖所有情况
总结
\(1.\) 插头定义在扫描线上方,定义处理前插头在左上的上方,处理完当前点后对应的扫描线图形后插头在右下的上方
\(2.\) 插头DP神题,注意分类讨论,一般分类标准为向右向下延伸,而向左向上的情况则通过在某一个点合并上面和左边传来的
// https://www.luogu.org/blog/dedicatus545/solution-p3272
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define hash deep_dark_fantasy
#define ll long long
#define MOD 20110520
using namespace std;
inline int read(){
int re=0,flag=1;char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-') flag=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
int n,m,x[150][150],cur,pre,ex,ey;
int st[2][300010];ll ans[2][300010],re;
int tot[2],bit[20],state[300010],st_tot,hash=300000;
struct edge{
int to,next;
}a[300010];
void insert(int now,ll val){
int p=now%hash;
for(int i=state[p];i;i=a[i].next){
if(st[cur][a[i].to]==now){
ans[cur][a[i].to]+=val;
ans[cur][a[i].to]%=MOD;return;
}
}
tot[cur]++;
a[++st_tot].to=tot[cur];
a[st_tot].next=state[p];
state[p]=st_tot;st[cur][tot[cur]]=now;ans[cur][tot[cur]]=val%MOD;
}
void dp(){
int i,j,k,down,right,now;ll val;
cur=0;tot[cur]=1;ans[cur][1]=1;st[cur][1]=0;
for(i=1;i<=n;i++){
for(j=1;j<=tot[cur];j++) st[cur][j]<<=2;
for(j=1;j<=m;j++){
memset(state,0,sizeof(state));st_tot=0;
pre=cur;cur^=1;tot[cur]=0;
for(k=1;k<=tot[pre];k++){
now=st[pre][k];val=ans[pre][k];
right=(now>>bit[j-1])%4;down=(now>>bit[j])%4;
if(!x[i][j]){//障碍格子
if(!down&&!right){
insert(now,val);continue;
}
}
if(!right&&!down){//第一种情况
if(x[i+1][j]&&x[i][j+1])
insert(now+((1<<bit[j-1])<<1)+((1<<bit[j])<<1),val);
if(x[i+1][j]) insert(now+(1<<bit[j-1]),val);
if(x[i][j+1]) insert(now+(1<<bit[j]),val);
}
if(right==1&&!down){//第三种情况
if(x[i][j+1]) insert(now-(1<<bit[j-1])+(1<<bit[j]),val);
if(x[i+1][j]) insert(now+(1<<bit[j-1]),val);
}
if(down==1&&!right){//第二种情况
if(x[i+1][j]) insert(now-(1<<bit[j])+(1<<bit[j-1]),val);
if(x[i][j+1]) insert(now+(1<<bit[j]),val);
}
if(right==2&&!down){//第五种情况
if(i==ex&&j==ey) re+=val,re%=MOD;
if(x[i][j+1]) insert(now-((1<<bit[j-1])<<1)+((1<<bit[j])<<1),val);
insert(now-((1<<bit[j-1])<<1),val);
}
if(down==2&&!right){//第四种情况
if(i==ex&&j==ey) re+=val,re%=MOD;
if(x[i+1][j]) insert(now-((1<<bit[j])<<1)+((1<<bit[j-1])<<1),val);
insert(now-((1<<bit[j])<<1),val);
}
if(down==1&&right==1){//第六种情况
if(i==ex&&j==ey) re+=val,re%=MOD;
insert(now-(1<<bit[j-1])-(1<<bit[j]),val);
}
}
}
}
}
int main(){//这道题的读入没有保证n>=m,所以我写了一个判断,来保证n>=m,具体操作就是把图旋转了九十度
int i,j;char ch;
n=read();m=read();
for(i=1;i<=20;i++) bit[i]=i<<1;
if(n>m){
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
ch=getchar();
while(ch!='*'&&ch!='_') ch=getchar();
x[i][j]=(ch=='_');
if(x[i][j]) ex=i,ey=j;
}
}
}
else{
swap(n,m);
for(i=m;i>0;i--){
for(j=1;j<=n;j++){
ch=getchar();
while(ch!='*'&&ch!='_') ch=getchar();
x[j][i]=(ch=='_');
if(x[j][i]&&((j>ex)||(j==ex&&i>ey))) ex=j,ey=i;
}
}
}
dp();
printf("%lld",re);
}
P3272 [SCOI2011]地板(插头DP)的更多相关文章
- bzoj 2331: [SCOI2011]地板 插头DP
2331: [SCOI2011]地板 Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 541 Solved: 239[Submit][Status] D ...
- 【BZOJ2331】[SCOI2011]地板 插头DP
[BZOJ2331][SCOI2011]地板 Description lxhgww的小名叫“小L”,这是因为他总是很喜欢L型的东西.小L家的客厅是一个的矩形,现在他想用L型的地板来铺满整个客厅,客厅里 ...
- 2331: [SCOI2011]地板 插头DP
国际惯例的题面:十分显然的插头DP.由于R*C<=100,所以min(R,C)<=10,然后就可以愉悦地状压啦.我们用三进制状压,0表示没有插头,1表示有一个必须延伸至少一格且拐弯的插头, ...
- 【BZOJ】2331: [SCOI2011]地板 插头DP
[题意]给定n*m的地板,有一些障碍格,要求用L型的方块不重不漏填满的方案数.L型方块是从一个方格向任意两个相邻方向延伸的方块,不能不延伸.n*m<=100. [算法]插头DP [题解]状态0表 ...
- BZOJ 2331 [SCOI2011]地板 ——插头DP
[题目分析] 经典题目,插头DP. switch 套 switch 代码瞬间清爽了. [代码] #include <cstdio> #include <cstring> #in ...
- [SCOI2011][bzoj2331] 地板 [插头dp]
题面: 传送门 思路: 插头dp基础教程 这个L形......第一眼看上去真的是丧病啊 但是仔细想想,实际上也就是拿一堆路径铺满一个棋盘,这个路径还是有限制的 那还有什么好说的,插头dp上啊[雾] 首 ...
- P3272 [SCOI2011]地板
\(\color{#0066ff}{ 题目描述 }\) lxhgww的小名叫"小L",这是因为他总是很喜欢L型的东西.小L家的客厅是一个R*C的矩形,现在他想用L型的地板来铺满整个 ...
- 洛谷P3272 [SCOI2011]地板(插头dp)
传送门 感谢大佬的教导->这里 容易注意到,本题的合法路径“L型地板”有一些特殊的地方:拐弯且仅拐弯一次. 这由于一条路径只有两种状态:拐弯过和没拐弯过,因此我们可以尝试着这样定义新的插头: 我 ...
- 插头dp小结
插头dp: \(A:\)插头dp是什么? \(B:\)一种基于连通性状态压缩的动态规划问题 \(A:\)请问有什么应用呢? \(B:\)各种网格覆盖问题,范围允许状压解决,常用于计算方案数与联通块权值 ...
随机推荐
- 部署和调优 2.1 squid正向代理
安装squid yum install -y squid Squid 官方网站为 http://www.squid-cache.org 打开注释掉的 cache_dir ufs / 缓存目录的位置,大 ...
- C语言学习笔记--动态库和静态库的使用
1.C语言中的链接器 (1)每个 C 语言源文件被编译后生成目标文件,这些目标文件最终要被链接在一起生成可执行文件. (2)链接器的主要作用是把各个模块之间相互引用的部分处理好,使得各个模块之间能够正 ...
- re.spilt
- php学习笔记-逻辑运算符
$a and $b 只有当$a和$b都是true才返回true,否则false. $a or $b 只要$a或者$b至少有一个是true则返回true.意思是或者$a是true,或者是$b是true, ...
- Django rest framework之序列化小结
最近在DRF的序列化上踩过了不少坑,特此结合官方文档记录下,方便日后查阅. [01]前言 serializers是什么?官网是这样的”Serializers allow complex d ...
- Redis了解
1. 使用Redis有哪些好处? (1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1) (2) 支持丰富数据类型,支持string,li ...
- Redis应用(django)
自定义使用redis 创建url 定义单例模式连接池 import redis # 连接池 POOL = redis.ConnectionPool(host='10.211.55.4', port=6 ...
- Python程序设计2——列表和元组
数据结构:更好的说法是从数据角度来说,结构化数据,就是说数据并不是随便摆放的,而是有一定结构的,这种特别的结构会带来某些算法上的性能优势,比如排序.查找等. 在Python中,最基本的数据结构是序列( ...
- Entity Framework Tutorial Basics(1):Introduction
以下系列文章为Entity Framework Turial Basics系列 http://www.entityframeworktutorial.net/EntityFramework5/enti ...
- backstop bsg6