题目描述

有一个m行n列的矩阵,用1*2的骨牌(可横放或竖放)完全覆盖,骨牌不能重叠,有多少种不同的覆盖的方法? 你只需要求出覆盖方法总数mod p的值即可。

输入格式

三个整数数n,m,p,m<=5,p<=10000,n<=10000

输出格式

一个整数:总数模p的结果


不难想到可以用状压来做这题。设dp(i,j)表示第i列放置情况为j的二进制表示,其中j的第k位为1时表示这玩意是一块竖着的骨牌的上半部分,为0则是其余的情况。我们考虑一下dp(i,j)可以由哪些状态转移而来。

设上一行的二进制表示为j,当前一行的为k。由于当j的某些位置为1时,k的这些位置也必须为1。为了在满足我们的定义的同时把j的1给转移下来,我们可以将j和k做一次按位或运算。此时数j|k中为0的部分就是放横着的骨牌的地方。显然j|k中为0的连续部分长度必须是偶数。所以我们转移的第一个条件就是:

1.j|k的每一段连续0的长度都必须为偶数

如果上一行的某一位是1,而当前一行的这一位也是1,那么不合法,不能转移。所以我们的第二个转移的条件就是:

2.j和k的相同位置不能都为1

怎么判断两个条件呢?

对于第二个条件,我们可以将j和k做一次按位与运算,如果得到的数不为0,即得到的数里面含有1,那么不合法:

if(j&k) continue;

对于第一个条件,我们只好O(m)地慢慢转移:

int odd=0,cnt=0;
for(register int l=0;l<m;l++)
if((j|k)>>l&1) odd|=cnt,cnt=0;
else cnt^=1;
if(odd|cnt) continue;

所以我们得到了一个时间复杂度为O(NM * 2^M * 2^M)=O(NM * 4^M)的算法。

#include<iostream>
#include<cstring>
#include<cstdio>
#define maxm 5
#define maxn 10001
using namespace std; int dp[maxn][1<<maxm];
int n,m,p; inline int read(){
register int x(0),f(1); register char c(getchar());
while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
} int main(){
n=read(),m=read(),p=read();
dp[0][0]=1;
for(register int i=1;i<=n;i++){
for(register int j=0;j<1<<m;j++){
for(register int k=0;k<1<<m;k++){
if(j&k) continue;
int odd=0,cnt=0;
for(register int l=0;l<m;l++)
if((j|k)>>l&1) odd|=cnt,cnt=0;
else cnt^=1;
if(odd|cnt) continue;
(dp[i][j]+=dp[i-1][k])%=p;
}
}
}
printf("%d\n",dp[n][0]);
return 0;
}

这个复杂度足够通过本题了。


对于这个算法有个小小的优化:

设函数f(j,k)=j|k,不难发现其定义域大小为2M2=4M而值域大小只有2M,所以我们对于一个f(j,k)其实重复算了2^M次。所以我们可以预处理出所有f(j,k):

for(register int i=0;i<1<<m;i++){
int odd=0,cnt=0;
for(register int j=0;j<m;j++)
if(i>>j&1) odd|=cnt,cnt=0;
else cnt^=1;
even[i]=odd|cnt?0:1;
}

然后在dp的过程中:

dp[0][0]=1;
for(register int i=1;i<=n;i++){
for(register int j=0;j<1<<m;j++){
for(register int k=0;k<1<<m;k++){
if(!(j&k)&&even[j|k]) (dp[i][j]+=dp[i-1][k])%=p;
}
}
}

可以把时间复杂度优化成O(N * 4^M+M * 2^M)

Zju1100 Mondriaan的更多相关文章

  1. [poj2411] Mondriaan's Dream (状压DP)

    状压DP Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One nigh ...

  2. POJ 题目2411 Mondriaan's Dream(状压DP)

    Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 13519   Accepted: 787 ...

  3. POJ 2411 Mondriaan&#39;s Dream

    状压DP Mondriaan's Dream Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 9938 Accepted: 575 ...

  4. POJ2411 Mondriaan's Dream

    Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, af ...

  5. 状压DP POJ 2411 Mondriaan'sDream

    题目传送门 /* 题意:一个h*w的矩阵(1<=h,w<=11),只能放1*2的模块,问完全覆盖的不同放发有多少种? 状态压缩DP第一道:dp[i][j] 代表第i行的j状态下的种数(状态 ...

  6. HDU 1400 (POJ 2411 ZOJ 1100)Mondriaan's Dream(DP + 状态压缩)

    Mondriaan's Dream Problem Description Squares and rectangles fascinated the famous Dutch painter Pie ...

  7. poj 2411 Mondriaan's Dream(状态压缩dp)

    Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, af ...

  8. poj 2411 Mondriaan&#39;s Dream 【dp】

    题目:id=2411" target="_blank">poj 2411 Mondriaan's Dream 题意:给出一个n*m的矩阵,让你用1*2的矩阵铺满,然 ...

  9. POJ2411 Mondriaan's Dream(状态压缩)

    Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 15295   Accepted: 882 ...

随机推荐

  1. linux操作系统及常用命令

    GUN:GUN is Not UnixGPL:General Public License.通用公共许可证,版权 Copyright,Copyleft 开源协议LGPL:lesserGPLv2GPLv ...

  2. .netcore3.1——应用AutoMapper

    多层架构中存在多种模型,如视图模型ViewModel,数据传输对你DTO,ORM对象等,这些数据在层与层之间进行传输必须涉及类型之间的转换. AutoMapper是一个对象-对象映射器,作用是通过设置 ...

  3. 测试平台MeterSphere源码入门

    前端代码结构 ├── package.json #Vue的模块依赖定义 ├── pom.xml #Maven前后端打包的定义与依赖 ├── public ├── src #前端核心代码 │ ├── a ...

  4. 使用swagger上传文件

    经常使用swagger,可以通过设置[ProducesResponseType]标记接口的返回信息:swagger也能通过接口的参数列表,自动获得发送的数据结构信息. 不过有一个例外,就是上传文件的时 ...

  5. 分布式零基础之--分布式CAP理论

    研究到分布式系统CAP理论,记录下来下回详细分析它: CAP是指三个单词的简称 C: 一致性(Consistence) 所有节点访问的都是同一份最新的数据副本. A: 可用性(Availability ...

  6. eclipse开启的时候adb.exe会自动开启么 怎么让它跟着eclipse自动开启

    会的,Eclipse 参数页中的 General > Startup and Shutdown 中默认 Android Development Tools 是自动激活的,它会启动 adb.exe ...

  7. Playwright VS Selenium VS Puppeteer VS Cypress

    参考:https://www.testim.io/blog/puppeteer-selenium-playwright-cypress-how-to-choose/ 这四款自动化测试框架在我们的公众号 ...

  8. linux 笔记的注意事项

    声明:本人Linux的笔记是根据<鸟哥私房菜>而写的 command [-option] parameter1 parameter2 ... command 是命令的名称: [ ]中括号是 ...

  9. 关于IP的相关计算

    不论是考研还是考各种计算机类的证,大家或多或少都会遇到网络部分的一种题型,大体的归类就是以下几种: 已知一个IP是192.XX.XX.XX,子网掩码是255.255.255.0,那么它的网络地址是多少 ...

  10. [学习笔记]Golang--基础数据类型

    1,不同类型的变量不能互相赋值或者操作,如var a int8 = 16var b int = 23c := a + b 会报错,且int虽然默认32位,但和int32是不同的类型 iota只在声明枚 ...