题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4332

题目意思:

用1*1*2的长方体构造一个中间为空的底面3*3的立体烟囱。

解题思路:

实际上就是poj上这道题的升华版。推荐先做那道题。

只不过本题的每一层相当于poj上那题的每一行,此题层数很多,所以很直白的想到用矩阵快速幂加速。

这类型的矩阵乘法做的比较少。

用二维矩阵表示两层之间的转移关系,第一维表示上一层的状态,第二维表示下一层的状态,作为基矩阵。每次乘以它就相当于加了一层。状态图和矩阵转移如下,虽然很丑,但还看的清。

0表示当前层不放,那么它下面的一层肯定要为1(并且还是竖着的1),

1表示当前层放,可以是平着,也可以是竖着。(最后在统计最后一层平放的情况,最后一层竖着放肯定不行,超过了)

因为要多次调用基矩阵的偶次方,故预处理给保存起来。

代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF 0x1f1f1f1f
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std; /*
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
*/ #define Maxn 300
#define M 1000000007 struct Mar
{
int r,c;
ll sa[Maxn][Maxn]; void init(int a,int b) //矩阵的初始化
{
r=a,c=b;
memset(sa,0,sizeof(sa));
} };
Mar mar[35]; //mar[][i][j] 表示从当前层i状态转到下一层的j状态的种数
//这种矩阵构造还是第一次见
ll ans[Maxn],tmp[Maxn];
int m; Mar operator *(const Mar &a,const Mar &b)
{
Mar cc;
cc.init(a.r,b.c); for(int k=0;k<=a.c;k++) //注意要从0开始,因为0也是一种状态,纠结了好半天
{
for(int i=0;i<=a.r;i++)
{
if(a.sa[i][k]==0) //矩阵优化加速,把a矩阵的列或b矩阵的行 作为第一个循环
continue;
for(int j=0;j<=b.c;j++)
{
if(b.sa[k][j]==0)
continue;
cc.sa[i][j]=(cc.sa[i][j]+a.sa[i][k]*b.sa[k][j])%M;
}
}
}
return cc;
}
bool can[Maxn]; bool ok(int st) //是否有含有偶数个1 是的话可以横着放
{
if(st==0)
return true;
int i=0;
while((st&(1<<i))&&(i<8)) //找到第一个不是1的位置
i++;
if(i>=8)
return true;
for(int j=i+1;j<=i+8;j++) //循环起来,最多只需找8位
{
if(st&(1<<(j%8))) //两个两个一找
{
if(st&(1<<((j+1)%8)))
j++;
else
return false;
}
}
return true;
}
void iscan()
{
memset(can,false,sizeof(can));
for(int i=0;i<m;i++)
if(ok(i)) //有偶数个连续的1
can[i]=true;
return ;
} void Initba()
{//mar[0]应该是base mar[1]为base^2 mar[2]为base^4
mar[0].init(m-1,m-1);
for(int i=0;i<m;i++)
for(int j=0;j<m;j++)
{
if((i|j)==m-1&&can[i&j])
mar[0].sa[i][j]=1;
}
mar[0].sa[m-1][m-1]=2;// 此时下面一层可以有两种放法,题目中的第一个样例
for(int i=1;i<32;i++) //先预处理起来,因为每次都要计算矩阵的话,很慢
mar[i]=mar[i-1]*mar[i-1];
}
void mul(int x)
{
memset(tmp,0,sizeof(tmp));
for(int i=0;i<m;i++) //奇数的话 乘以一个
{
for(int j=0;j<m;j++)
tmp[i]=(ans[j]*mar[x].sa[j][i]+tmp[i])%M;
}
for(int i=0;i<m;i++)
ans[i]=tmp[i];
} void quick(int n)
{
memset(ans,0,sizeof(ans));
ans[m-1]=1; //表示第一层必须全为1才可能在上面放,1是一个标识,表示之前的0层的数量
n--; //第一层已经放好了
for(int i=0;n&&i<32;i++)
if(n&(1<<i))
mul(i);
} int main()
{
m=1<<8;
// printf("%d\n",m);
iscan();
Initba();
int n,t;
scanf("%d",&t);
for(int ca=1;ca<=t;ca++)
{
scanf("%d",&n);
quick(n);
ll sum=0;
for(int i=0;i<m;i++)
if(can[i]) //最后一层可以平铺
{
sum=(sum+ans[i])%M;
if(i==m-1) //最后一层有两种平铺法
sum=(sum+ans[i])%M;
}
printf("Case %d: %I64d\n",ca,sum);
}
return 0;
}

状态压缩+矩阵乘法hdu-4332-Constructing Chimney的更多相关文章

  1. luogu1357 花园 状态压缩 矩阵快速幂

    题目大意 小L有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为1~N(2<=N<=10^15).他的环形花园每天都会换一个新花样,但他的花园都不外乎一个规则,任意相邻M(2<= ...

  2. 【状态压缩DP】HDU 4352 XHXJ'S LIS

    题目大意 Vjudge链接 定义一个数的内部LIS长度表示这个数每个数位构成的序列的LIS长度,给出区间\([l,r]\),求区间内内部LIS长度为\(k\)的数的个数. 输入格式 第一行给出数据组数 ...

  3. 矩阵乘法 --- hdu 4920 : Matrix multiplication

    Matrix multiplication Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/ ...

  4. 洛谷P1357 花园(状态压缩 + 矩阵快速幂加速递推)

    题目链接:传送门 题目: 题目描述 小L有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为1~N(<=N<=^).他的环形花园每天都会换一个新花样,但他的花园都不外乎一个规则,任意相邻 ...

  5. HDU - 6185 :Covering(矩阵乘法&状态压缩)

    Bob's school has a big playground, boys and girls always play games here after school. To protect bo ...

  6. HDU 5768 Lucky7 (容斥原理 + 中国剩余定理 + 状态压缩 + 带膜乘法)

    题意:……应该不用我说了,看起来就很容斥原理,很中国剩余定理…… 方法:因为题目中的n最大是15,使用状态压缩可以将所有的组合都举出来,然后再拆开成数组,进行中国剩余定理的运算,中国剩余定理能够求出同 ...

  7. HDU 4921 Map DFS+状态压缩+乘法计数

    算最多十条链,能截取某前缀段,每种方案都可以算出一个权值,每种方案的概率都是总数分之一,问最后能构成的所有可能方案数. 对计数原理不太敏感,知道是DFS先把链求出来,但是想怎么统计方案的时候想了好久, ...

  8. HDU 5607 graph(DP+矩阵乘法)

    [题目链接] http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=663&pid=1002 [题意] 给定一个有向 ...

  9. HDU 3681 Prison Break(状态压缩dp + BFS)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3681 前些天花时间看到的题目,但写出不来,弱弱的放弃了.没想到现在学弟居然写出这种代码来,大吃一惊附加 ...

随机推荐

  1. Ex 5_22 在此我们基于以下性质给出一个新的最小生成树算法..._第九次作业

    (a)设环的顶点集为V, e(u,v)为权最重的边,若把V分成两部分V1,V2.其中V1包含u,V2包含v,因为V是一个环,因此,至少存在两条把u和v连接起来的边.因此,除了e之外,至少还存在另一条边 ...

  2. android getActivity.findViewById获取ListView 返回NULL

    在控件ID正确的情况下,检查是否在实例化布局文件之后,获取LISTVIEW, 先inflate找layout下布局文件,并实例化后才能获得Listview的ID demo: public class ...

  3. oracle进阶之connect by笔记

    本博客是自己在学习和工作途中的积累与总结,仅供自己参考,也欢迎大家转载,转载时请注明出处. http://www.cnblogs.com/king-xg/p/6794562.html 如果觉得对您有帮 ...

  4. python+selenium十二:一个输入框双层input标签

    先点击第一个,再对第二个进行操作,否则操作失败 driver.find_element_by_css_selector(".pwd").click()driver.find_ele ...

  5. Oracle学习笔记--第3章 使用sql*plus工具

    使用sql*plus工具 1.sqlplus连接方式示例 sqlplus system/123[as sysdba]; 2.查看表结构命令;desc[ribe] e.g.      desc scot ...

  6. Kotlin 喧嚣过后,谈谈 Java 程序员未来的出路

    http://blog.jobbole.com/111422 Java 生态圈 Java 的生态环境开放.自由,在Sun/Oracle.Google.Apache.Eclipse基金会等各大厂商,还有 ...

  7. vtiger7安装设置

    安装界面一直报错 其实是设置的问题 error_reporting:E_WARNING & ~E_NOTICE & ~E_DEPRECATED max_execution_time:6 ...

  8. dll反编译工具总结

    有好多.net程序有加密狗或者有验证,如果exe或dll没有做过特殊处理,破解.net程序其实很简单,不过你要有足够的耐心! 我只做个简单的小例子,把公司的软件破解了,不要被老大知道,吼吼~~~~ 1 ...

  9. xhprof扩展安装与使用

    目录 一.xhprof扩展安装步骤 二.xhprof的使用 总结 参考资料 一.xhprof扩展安装步骤 xhprof是PHP的一个扩展,最好也直接安装上graphviz图形绘制工具(用于xhprof ...

  10. rdesktop方法(Linux to Windows)

    我的配置: rdesktop -g 960x1080 -a 16 -u aura-bd -0 192.168.62.241 1. 准备工作: ubuntu端: sudo apt-get install ...