题目描述

有一个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. monkey 基本用法

    monkey测试步骤: 一.使用模拟机 1.安装好虚拟机,比如说天天模拟机.夜神模拟机.雷神模拟机 2.将需要测试的APK装在虚拟机上 3.cmd>adb shell 连接模拟机 4.输入命令m ...

  2. 技术基础 | 改进版的Apache Cassandra客户端请求路由

    最近我们在客户端的驱动程序中引入了一些变更,这些变更会影响传入的请求在Apache Cassandra集群内的分发方式.   新的默认负载均衡算法即将随驱动程序推出,这些算法将有助于缩短长尾延迟,并提 ...

  3. 一个shell程序

    使用vi写一个shell程序 touch cdlog  echo "cd /app/mycrm/log" >> cdlog  chmod +x cdlog   执行: ...

  4. Python 函数对象的本质

    Python 函数对象本质上是 function 类的实例. 1 从示例说起 def factorial(n): '''return n!''' return 1 if n < 2 else n ...

  5. 【k8s实战一】Jenkins 部署应用到 Kubernetes

    [k8s实战一]Jenkins 部署应用到 Kubernetes 01 本文主旨 目标是演示整个Jenkins从源码构建镜像到部署镜像到Kubernetes集群过程. 为了简化流程与容易重现文中效果, ...

  6. web项目中使用火狐浏览器导出文件时文件名乱码

    原因 主要是编码的问题.在设置文件名称前,加上判断.判断下载者使用的浏览器,如果不是火狐浏览器,则对文件名称进行UTF8编码;如果是火狐浏览器,则不对文件名称进行操作. 解决办法 文件名称编码时进行判 ...

  7. request.getContextPath()返回值问题

    转自:http://blog.sina.com.cn/s/blog_6cbe0cff0101j6jl.html request.getContextPath()是在开发Web项目时,经常用到的方法,其 ...

  8. [leetcode712]204. Count Primes寻找范围内的素数

    厄拉多塞筛选法,就是哈希表记录素数的倍数 public int countPrimes(int n) { /* 牛逼哄哄的厄拉多塞筛选法 就是从2开始,每找到一个素数,就把n以内的这个数的倍数排除 记 ...

  9. java Swing组件随着窗口拖动等比移动或等比放大

    实现原理很简单, 1清空布局(使用绝对布局) 2添加监听器(监听窗口是否被拖动) 3在监听器里面动态调整 组件的位置 效果如下: 拖动之后效果: 代码实现: import java.awt.Event ...

  10. editmd输出到前端显示

    官方案例:html-preview-markdown-to-html.html 输出后台数据显示在前端,格式化内容<!DOCTYPE html> <html lang="z ...