HDU_4332 Constructing Chimney
来源:互联网 发布:mac 最新u盘启动盘 编辑:程序博客网 时间:2024/05/16 19:49
http://acm.hdu.edu.cn/showproblem.php?pid=4332
题意:
有一块3*3的空地,要求在上面建一个建筑物,但是要求中间的那块必须空着,现在只有1*1*2的砖,问你要建成高度为N的建筑物共有多少种不同的方法。N<=1e9
思路:
看到这么大的N就应该想到用矩阵二分幂来求,那么很显然就是dp了,因为砖只有1*1*2的一种,在对一层进行排放的时候我们只需关心它的上一层的摆放情况就好了, 因此我们需要用一个8bit的二进制来记录上一层的状态,接下去我们就要构造出一个转移矩阵。先考虑一下复杂度:O(256^3*log(n) ),这样的复杂度有有可能会超时(但是事实是题目给的20s时限这样的复杂度也可以过)。这样我们就希望能优化上面的复杂度,logn的矩阵乘法是不能优化了,那么我们就想优化前面的256^3,看是否其中的有些状态是可以去掉的。考虑题目中的8个位置正好是矩阵的外圈,用8位的2进制表示时有对称性,如果将4个对称的部分合在一起,那么状态数就会变成只有256/4种(其实有70种),这样我们就可以将复杂度降低了。最后的工作就是构造出矩阵,然后用矩阵二分幂求解。 在构造矩阵的时候要注意去掉重复的。
代码:
#include <stdio.h>#include <string.h>#include <map>#include <algorithm>typedef __int64 LL ;const LL Mod = 1000000007LL ;const int m = (1 << 8) ;const int mm = 70 ;bool ok[m] ;int a[8] , N ;int min[m] ;struct Matrix{ LL mat[mm][mm] ; void init(){ memset( mat, 0 ,sizeof(mat) ) ; }}M[31] , res ,mid ;LL ans[mm] ;bool is_ok(int s){ if( s==0 ) return true ; if( s==m-1 ) return true ; int val[8] ; int i ; for(i=0;i<8;i++) if( s&a[i] ) val[i] = 1 ; else val[i] = 0; i = 0 ; while( val[i] ) ++ i ; for(int ii=0;ii<8;ii++ ){ if( val[ (ii+i)%8 ] == 0 ) continue ; if( ii+1<8 && val[ (ii+i+1)%8 ] ){ ii ++ ; } else return false ; } return true ;}int getmin( int n ){ int val[8] ; for(int i=0;i<8;i++) { if( n&a[i] ) val[i] = 1 ; else val[i] = 0 ; } int v = 0 ; int res = n ; for(int ii=0;ii<8;ii++) if( val[ (2+ii)%8 ] ) v |= a[ ii ] ; if( res > v ) res = v ; v = 0 ; for(int ii=0;ii<8;ii++) if( val[ (4+ii)%8 ] ) v |= a[ ii ] ; if( res > v ) res =v ; v = 0 ; for(int ii=0;ii<8;ii++) if( val[ (6+ii)%8 ] ) v |= a[ ii ] ; if( res > v ) res =v ; return res ;}std::map<int , int> mp ;bool vis[m + 10][m + 10] ;void deal(int sou , int to){ int val[8] ; for(int i=0;i<8;i++){ if( to&a[i] ) val[i] = 1 ; else val[i] = 0 ; } LL v1 , v2 ; v1 = sou ; for(int j=0; j<=6;j+=2 ){ v2 = 0 ; for(int jj=0;jj<8;jj++){ if( val[ (j+jj)%8 ] ) v2 |= a[jj] ; } if( ( v1|v2 )==m-1 && ok[ v1&v2 ] && !vis[v1][v2] ){ M[0].mat[ mp[ min[v1] ] ][ mp[ min[v2] ] ] ++ ; vis[v1][v2] = 1 ; } }}void build_matrix(){ M[0].init() ; memset( vis , 0 , sizeof(vis) ); std::map<int, int>::iterator it1 ,it2 ; for( it1 = mp.begin() ; it1!=mp.end() ; it1++ ){ for( it2=mp.begin() ; it2!=mp.end() ; it2++ ){ deal( it1->first , it2->first ) ; } } M[0].mat[mm-1][mm-1] = 2 ; for(int ii=1;ii<=30;ii++){ for(int i=0;i<mm;i++){ for(int j=0;j<mm;j++){ mid.mat[i][j] = 0 ; for(int k=0;k<mm;k++){ mid.mat[i][j] = ( mid.mat[i][j] + M[ii-1].mat[i][k] * M[ii-1].mat[k][j] % Mod ) % Mod ; } } } M[ii] = mid ; }}void init(){ a[0] = 1 ; for(int i=1;i<8;i++) a[i] = a[i-1]<<1 ; for(int i=0;i<m;i++) min[i] = getmin(i) ; for(int i=0;i<m;i++){ ok[i] = is_ok( i ) ; mp[ min[i] ] = 1 ; } std::map<int,int>::iterator it = mp.begin() ; int ss = 0 ; for( it ; it != mp.end(); it ++ ){ it->second = ss ++ ; } build_matrix() ;}void calc( int n ){ memset( ans , 0 , sizeof(ans) ) ; int jj = 0 ; ans[ mm-1 ] = 1 ; LL CC[mm] ; while( n ){ if( n&1 ){ for(int i=0;i<mm;i++){ CC[i] = 0; for(int j=0;j<mm;j++){ CC[i] = ( CC[i] + ans[j] * M[jj].mat[i][j]% Mod ) % Mod ; } } for(int i=0;i<mm;i++) ans[i] = CC[i] ; } n >>= 1 ; jj ++ ; }}int main(){ init() ; int T ;scanf("%d",&T) ; int cas = 0 ; while( T-- ){ scanf("%d",&N) ; calc(N + 1) ; printf("Case %d: %I64d\n",++cas,ans[0] ) ; } return 0 ;}
- HDU_4332 Constructing Chimney
- hdu - 4332 - Constructing Chimney - 状态压缩dp
- [状压 + 矩阵乘法] HDU 4332 Constructing Chimney
- 状态压缩+矩阵乘法hdu-4332-Constructing Chimney
- Constructing Roads*
- Constructing Roads
- Constructing Roads
- Constructing Roads
- Constructing Roads
- Constructing Roads
- Constructing Roads
- Constructing Roads
- Constructing Roads
- Constructing Roads
- Constructing Roadster
- Constructing Roads
- Constructing Roads
- Constructing Roads
- HeadFirst设计模式读书笔记--观察者模式(2)(二)
- JavaScript世界的一等公民 - 函数
- Oracle 升级(10.2.0.1 --> 10.2.0.4) 包含升级包
- 网络流算法--Ford-Fulkerson方法及其多种实现
- EditText相关内容
- HDU_4332 Constructing Chimney
- 初学 Delphi 嵌入汇编[2] - 汇编语言关键字
- complex
- SQLSERVER 创建表 但其最大行大小 超过了每行的最大字节数(8060)
- 系统之间通讯方式—SOAP(web service)
- 初学 Delphi 嵌入汇编[3] - 第一个 Delphi 与汇编的例子
- 野指针
- ubuntu启动eclipse失败
- 做Android广告的惨败总结