状态压缩+矩阵乘法hdu-4332-Constructing Chimney
题目链接:
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的更多相关文章
- luogu1357 花园 状态压缩 矩阵快速幂
题目大意 小L有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为1~N(2<=N<=10^15).他的环形花园每天都会换一个新花样,但他的花园都不外乎一个规则,任意相邻M(2<= ...
- 【状态压缩DP】HDU 4352 XHXJ'S LIS
题目大意 Vjudge链接 定义一个数的内部LIS长度表示这个数每个数位构成的序列的LIS长度,给出区间\([l,r]\),求区间内内部LIS长度为\(k\)的数的个数. 输入格式 第一行给出数据组数 ...
- 矩阵乘法 --- hdu 4920 : Matrix multiplication
Matrix multiplication Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/ ...
- 洛谷P1357 花园(状态压缩 + 矩阵快速幂加速递推)
题目链接:传送门 题目: 题目描述 小L有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为1~N(<=N<=^).他的环形花园每天都会换一个新花样,但他的花园都不外乎一个规则,任意相邻 ...
- HDU - 6185 :Covering(矩阵乘法&状态压缩)
Bob's school has a big playground, boys and girls always play games here after school. To protect bo ...
- HDU 5768 Lucky7 (容斥原理 + 中国剩余定理 + 状态压缩 + 带膜乘法)
题意:……应该不用我说了,看起来就很容斥原理,很中国剩余定理…… 方法:因为题目中的n最大是15,使用状态压缩可以将所有的组合都举出来,然后再拆开成数组,进行中国剩余定理的运算,中国剩余定理能够求出同 ...
- HDU 4921 Map DFS+状态压缩+乘法计数
算最多十条链,能截取某前缀段,每种方案都可以算出一个权值,每种方案的概率都是总数分之一,问最后能构成的所有可能方案数. 对计数原理不太敏感,知道是DFS先把链求出来,但是想怎么统计方案的时候想了好久, ...
- HDU 5607 graph(DP+矩阵乘法)
[题目链接] http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=663&pid=1002 [题意] 给定一个有向 ...
- HDU 3681 Prison Break(状态压缩dp + BFS)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3681 前些天花时间看到的题目,但写出不来,弱弱的放弃了.没想到现在学弟居然写出这种代码来,大吃一惊附加 ...
随机推荐
- 经典SQL语句大全(转)
SQL语句参考,包含Access.MySQL 以及 SQL Server 基础 创建数据库 CREATE DATABASE database-name 删除数据库 drop database dbna ...
- GBDT、XGBOOST、LightGBM调参数
总的认识: LightGBM > XGBOOST > GBDT 都是调参数比较麻烦. GBDT分类的最佳调参数的讲解: Gradient Boosting Machine(GBM)调参 ...
- LeetCode(45): 跳跃游戏 II
Hard! 题目描述: 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 你的目标是使用最少的跳跃次数到达数组的最后一个位置. 示例: 输入: [ ...
- LeetCode(5):最长回文子串
Medium! 题目描述: 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 长度最长为1000. 示例: 输入: "babad" 输出: "bab&quo ...
- 【ES】学习8-聚合1
参考资料: https://elasticsearch.cn/book/elasticsearch_definitive_guide_2.x/_combining_the_two.html 特定概念: ...
- 成员变量传参,jion方法的使用
package charpter06; //MyThread02和MyThread01两个类 相互调用的结果public class MyThread01 extends Thread { // 用全 ...
- PowerDesigner表创建脚本双引号问题
在使用PowerDesigner表属性的Preview查看创建脚本的时候,发现大多表名和字段名都加上了双引号,而且有引号的都是大小写混合的,导致创建的表里,表名和字段名也都是大小写混合的. 在一番搜索 ...
- poj 2349 求MST中第S大的权值
题目大意: 有一些炮台,如果这个炮台有卫星接收器,那么任意两个有卫星接收器的炮台可以通信,不受距离限制:否者,两个炮台之间只能通过对讲机通信,这是受距离限制的.要买一种对讲机,用在需要的炮台上,要求所 ...
- ubuntu ufw防火墙软件的配置入门
顺便,一条龙作完安全吧. ufw的使用,是比iptables简单.但只能作简单的事儿,更改简单的netfilter里的iptable里的记录.难点的,可能还是得iptables原生命令. 自打2.4版 ...
- Springboot 2.0 - 集成redis
序 最近在入门SpringBoot,然后在感慨 SpringBoot较于Spring真的方便多时,顺便记录下自己在集成redis时的一些想法. 1.从springboot官网查看redis的依赖包 & ...