题目链接:

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

题目意思:

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

解题思路:

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

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

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

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

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

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

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

代码:

  1. #include<iostream>
  2. #include<cmath>
  3. #include<cstdio>
  4. #include<cstdlib>
  5. #include<string>
  6. #include<cstring>
  7. #include<algorithm>
  8. #include<vector>
  9. #include<map>
  10. #include<set>
  11. #include<stack>
  12. #include<list>
  13. #include<queue>
  14. #define eps 1e-6
  15. #define INF 0x1f1f1f1f
  16. #define PI acos(-1.0)
  17. #define ll __int64
  18. #define lson l,m,(rt<<1)
  19. #define rson m+1,r,(rt<<1)|1
  20. //#pragma comment(linker, "/STACK:1024000000,1024000000")
  21. using namespace std;
  22.  
  23. /*
  24. freopen("data.in","r",stdin);
  25. freopen("data.out","w",stdout);
  26. */
  27.  
  28. #define Maxn 300
  29. #define M 1000000007
  30.  
  31. struct Mar
  32. {
  33. int r,c;
  34. ll sa[Maxn][Maxn];
  35.  
  36. void init(int a,int b) //矩阵的初始化
  37. {
  38. r=a,c=b;
  39. memset(sa,0,sizeof(sa));
  40. }
  41.  
  42. };
  43. Mar mar[35]; //mar[][i][j] 表示从当前层i状态转到下一层的j状态的种数
  44. //这种矩阵构造还是第一次见
  45. ll ans[Maxn],tmp[Maxn];
  46. int m;
  47.  
  48. Mar operator *(const Mar &a,const Mar &b)
  49. {
  50. Mar cc;
  51. cc.init(a.r,b.c);
  52.  
  53. for(int k=0;k<=a.c;k++) //注意要从0开始,因为0也是一种状态,纠结了好半天
  54. {
  55. for(int i=0;i<=a.r;i++)
  56. {
  57. if(a.sa[i][k]==0) //矩阵优化加速,把a矩阵的列或b矩阵的行 作为第一个循环
  58. continue;
  59. for(int j=0;j<=b.c;j++)
  60. {
  61. if(b.sa[k][j]==0)
  62. continue;
  63. cc.sa[i][j]=(cc.sa[i][j]+a.sa[i][k]*b.sa[k][j])%M;
  64. }
  65. }
  66. }
  67. return cc;
  68. }
  69. bool can[Maxn];
  70.  
  71. bool ok(int st) //是否有含有偶数个1 是的话可以横着放
  72. {
  73. if(st==0)
  74. return true;
  75. int i=0;
  76. while((st&(1<<i))&&(i<8)) //找到第一个不是1的位置
  77. i++;
  78. if(i>=8)
  79. return true;
  80. for(int j=i+1;j<=i+8;j++) //循环起来,最多只需找8位
  81. {
  82. if(st&(1<<(j%8))) //两个两个一找
  83. {
  84. if(st&(1<<((j+1)%8)))
  85. j++;
  86. else
  87. return false;
  88. }
  89. }
  90. return true;
  91. }
  92. void iscan()
  93. {
  94. memset(can,false,sizeof(can));
  95. for(int i=0;i<m;i++)
  96. if(ok(i)) //有偶数个连续的1
  97. can[i]=true;
  98. return ;
  99. }
  100.  
  101. void Initba()
  102. {//mar[0]应该是base mar[1]为base^2 mar[2]为base^4
  103. mar[0].init(m-1,m-1);
  104. for(int i=0;i<m;i++)
  105. for(int j=0;j<m;j++)
  106. {
  107. if((i|j)==m-1&&can[i&j])
  108. mar[0].sa[i][j]=1;
  109. }
  110. mar[0].sa[m-1][m-1]=2;// 此时下面一层可以有两种放法,题目中的第一个样例
  111. for(int i=1;i<32;i++) //先预处理起来,因为每次都要计算矩阵的话,很慢
  112. mar[i]=mar[i-1]*mar[i-1];
  113. }
  114. void mul(int x)
  115. {
  116. memset(tmp,0,sizeof(tmp));
  117. for(int i=0;i<m;i++) //奇数的话 乘以一个
  118. {
  119. for(int j=0;j<m;j++)
  120. tmp[i]=(ans[j]*mar[x].sa[j][i]+tmp[i])%M;
  121. }
  122. for(int i=0;i<m;i++)
  123. ans[i]=tmp[i];
  124. }
  125.  
  126. void quick(int n)
  127. {
  128. memset(ans,0,sizeof(ans));
  129. ans[m-1]=1; //表示第一层必须全为1才可能在上面放,1是一个标识,表示之前的0层的数量
  130. n--; //第一层已经放好了
  131. for(int i=0;n&&i<32;i++)
  132. if(n&(1<<i))
  133. mul(i);
  134. }
  135.  
  136. int main()
  137. {
  138. m=1<<8;
  139. // printf("%d\n",m);
  140. iscan();
  141. Initba();
  142. int n,t;
  143. scanf("%d",&t);
  144. for(int ca=1;ca<=t;ca++)
  145. {
  146. scanf("%d",&n);
  147. quick(n);
  148. ll sum=0;
  149. for(int i=0;i<m;i++)
  150. if(can[i]) //最后一层可以平铺
  151. {
  152. sum=(sum+ans[i])%M;
  153. if(i==m-1) //最后一层有两种平铺法
  154. sum=(sum+ans[i])%M;
  155. }
  156. printf("Case %d: %I64d\n",ca,sum);
  157. }
  158. return 0;
  159. }

状态压缩+矩阵乘法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. 经典SQL语句大全(转)

    SQL语句参考,包含Access.MySQL 以及 SQL Server 基础 创建数据库 CREATE DATABASE database-name 删除数据库 drop database dbna ...

  2. GBDT、XGBOOST、LightGBM调参数

    总的认识: LightGBM  > XGBOOST  > GBDT 都是调参数比较麻烦. GBDT分类的最佳调参数的讲解: Gradient Boosting Machine(GBM)调参 ...

  3. LeetCode(45): 跳跃游戏 II

    Hard! 题目描述: 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 你的目标是使用最少的跳跃次数到达数组的最后一个位置. 示例: 输入: [ ...

  4. LeetCode(5):最长回文子串

    Medium! 题目描述: 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 长度最长为1000. 示例: 输入: "babad" 输出: "bab&quo ...

  5. 【ES】学习8-聚合1

    参考资料: https://elasticsearch.cn/book/elasticsearch_definitive_guide_2.x/_combining_the_two.html 特定概念: ...

  6. 成员变量传参,jion方法的使用

    package charpter06; //MyThread02和MyThread01两个类 相互调用的结果public class MyThread01 extends Thread { // 用全 ...

  7. PowerDesigner表创建脚本双引号问题

    在使用PowerDesigner表属性的Preview查看创建脚本的时候,发现大多表名和字段名都加上了双引号,而且有引号的都是大小写混合的,导致创建的表里,表名和字段名也都是大小写混合的. 在一番搜索 ...

  8. poj 2349 求MST中第S大的权值

    题目大意: 有一些炮台,如果这个炮台有卫星接收器,那么任意两个有卫星接收器的炮台可以通信,不受距离限制:否者,两个炮台之间只能通过对讲机通信,这是受距离限制的.要买一种对讲机,用在需要的炮台上,要求所 ...

  9. ubuntu ufw防火墙软件的配置入门

    顺便,一条龙作完安全吧. ufw的使用,是比iptables简单.但只能作简单的事儿,更改简单的netfilter里的iptable里的记录.难点的,可能还是得iptables原生命令. 自打2.4版 ...

  10. Springboot 2.0 - 集成redis

    序 最近在入门SpringBoot,然后在感慨 SpringBoot较于Spring真的方便多时,顺便记录下自己在集成redis时的一些想法. 1.从springboot官网查看redis的依赖包 & ...