点头OJ 1033 . 骨牌覆盖 V2 ( 状态压缩 + 矩阵快速幂 )

举报
Linux猿 发表于 2021/08/05 00:02:39 2021/08/05
【摘要】 题目链接~~> 做题感悟:先前做过一个类似的题,是俄罗斯的一道区域赛的题目,也是用的状态压缩 + 矩阵快速幂。 解题思路:状态压缩 + 矩阵快速幂                 构造一个矩阵 B [ i ] [ j ] 代表状态 i ,与状态 j 是否合法,j 代表上一行的状态,如...

题目链接~~>

做题感悟:先前做过一个类似的题,是俄罗斯的一道区域赛的题目,也是用的状态压缩 + 矩阵快速幂。

解题思路:状态压缩 + 矩阵快速幂

                构造一个矩阵 B [ i ] [ j ] 代表状态 i ,与状态 j 是否合法,j 代表上一行的状态,如果合法为 1 ,否则为 0 ,这样如果再得到初始各种状态的方案数的矩阵 A ,A 只有一列 ,这样 B * A 就是第二行各种状态对应 的方案数 。这样再加上矩阵快速幂就解决了。


代码:


  
  1. #include<iostream>
  2. #include<sstream>
  3. #include<map>
  4. #include<cmath>
  5. #include<fstream>
  6. #include<queue>
  7. #include<vector>
  8. #include<sstream>
  9. #include<cstring>
  10. #include<cstdio>
  11. #include<stack>
  12. #include<bitset>
  13. #include<ctime>
  14. #include<string>
  15. #include<cctype>
  16. #include<iomanip>
  17. #include<algorithm>
  18. using namespace std ;
  19. #define INT long long int
  20. #define L(x) (x * 2)
  21. #define R(x) (x * 2 + 1)
  22. const int INF = 0x3f3f3f3f ;
  23. const double esp = 0.00000000001 ;
  24. const double PI = acos(-1.0) ;
  25. const INT mod = 1000000007 ;
  26. const int MY = (1<<5) + 5 ;
  27. const int MX = (1<<13) + 5 ;
  28. const int S = 20 ;
  29. int n ,m ;
  30. INT key[50] ;
  31. struct M
  32. {
  33. INT p[32][32] ;
  34. M()
  35. {
  36. memset(p ,0 ,sizeof(p)) ;
  37. }
  38. void init()
  39. {
  40. for(int i = 0 ;i < (1<<m) ; ++i)
  41. p[i][i] = 1 ;
  42. }
  43. M operator *(const M& a)
  44. {
  45. M c ;
  46. for(int i = 0 ;i < (1<<m) ; ++i)
  47. for(int k = 0 ;k < (1<<m) ; ++k)
  48. if(p[i][k])
  49. for(int j = 0 ;j < (1<<m) ; ++j)
  50. c.p[i][j] = (c.p[i][j] + p[i][k]*a.p[k][j])%mod ;
  51. return c ;
  52. }
  53. };
  54. M pow(M a ,int k) // 矩阵快速幂
  55. {
  56. M b ;
  57. b.init() ;
  58. while(k)
  59. {
  60. if(k&1) b = a * b ;
  61. a = a * a ;
  62. k >>= 1 ;
  63. }
  64. return b ;
  65. }
  66. void dfs(int S ,int cnt ,int tx ,int S1 ,M& c)
  67. {
  68. if(cnt == m)
  69. {
  70. c.p[S][tx] = 1 ;
  71. if(S1 == 0) key[S] = 1 ;
  72. return ;
  73. }
  74. if(cnt + 2 <= m && !(S&(1<<cnt)) && !(S&(1<<(cnt+1))))
  75. dfs(S|(1<<cnt)|(1<<(cnt+1)) ,cnt+2 ,tx ,S1 ,c) ;
  76. dfs(S ,cnt+1 ,tx ,S1 ,c) ;
  77. }
  78. int main()
  79. {
  80. //freopen("input.txt" ,"r" ,stdin) ;
  81. while(~scanf("%d%d" ,&n ,&m))
  82. {
  83. M c ;
  84. for(int i = 0 ;i < (1<<m) ; ++i) // 处理各种对应的状态 同时初始化第一行的状态
  85. dfs((~i)&((1<<m)-1) ,0 ,i ,(~i)&((1<<m)-1) ,c) ;
  86. M b = pow(c ,n-1) ;
  87. INT ans = 0 ;
  88. for(int i = 0 ;i < (1<<m) ; ++i)
  89. ans = (ans + b.p[(1<<m)-1][i]*key[i])%mod ;
  90. cout<<ans%mod<<endl ;
  91. }
  92. return 0 ;
  93. }






文章来源: blog.csdn.net,作者:Linux猿,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/nyist_zxp/article/details/41245003

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。