hihocoder第42周 k*N骨牌覆盖(状态dp+矩阵快速幂)

上周的3*N的骨牌,因为状态只有8中,所以我们可以手算出状态转移的矩阵

但是这周是k*N,状态矩阵不好手算,都是我们改成用程序自动生成一个状态转移的矩阵就行了,然后用这个矩阵进行快速幂即可

枚举枚举上下两行的状态,然后判断上一行的状态能不能转移为这一行的状态

如果上一行的某个位置为0,那么这一行的该位置必须为1

如果上一行的某个位置为1,那么这一行的该位置可以为0

如果上一行的某个位置为1,且这一行的该位置为1, 那么上下两行该位置相邻的位置也得为1

根据这三条规则判断状态能不能转移成功,然后生成矩阵

因为状态矩阵很大,不能够开成局部变量,所以一律开成全局的,函数的返回值全部改成void

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #include <algorithm>
  5 #include <iostream>
  6 #include <queue>
  7 #include <stack>
  8 #include <vector>
  9 #include <map>
 10 #include <set>
 11 #include <string>
 12 #include <math.h>
 13 using namespace std;
 14 #pragma warning(disable:4996)
 15 typedef long long LL;
 16 const int INF = 1 << 30;
 17 const int MOD = 12357;
 18 const int N = 1 << 8;
 19 int n, k;
 20 struct Matrix
 21 {
 22     int mat[N][N];
 23     void makeUnit()
 24     {
 25         int m = (1 << k);
 26         for (int i = 0; i < m; ++i)
 27         {
 28             for (int j = 0; j < m; ++j)
 29                 mat[i][j] = (i == j);
 30         }
 31     }
 32     void makeZero()
 33     {
 34         int m = 1 << k;
 35         for (int i = 0; i < m; ++i)
 36         {
 37             for (int j = 0; j < m; ++j)
 38                 mat[i][j] = 0;
 39         }
 40     }
 41 }a, ret1, ret2;
 42 void copy(Matrix &des, const Matrix &s)
 43 {
 44     int m = 1 << k;
 45     for (int i = 0; i < m; ++i)
 46     {
 47         for (int j = 0; j < m; ++j)
 48             des.mat[i][j] = s.mat[i][j];
 49     }
 50 }
 51 void dfs(int x, int y, int col)//这个题目提示的矩阵生成方法,挺厉害的
 52 {
 53     if (col == k)
 54     {
 55         a.mat[y][x] = 1;
 56         return;
 57     }
 58     dfs(x << 1, y << 1 | 1, col + 1);
 59     dfs(x << 1 | 1, y << 1, col + 1);
 60     if (col + 2 <= k)
 61         dfs((x << 2) + 3, (y << 2) + 3, col + 2);
 62 }
 63 void multiply(const Matrix &lhs, const Matrix &rhs)
 64 {
 65     ret2.makeZero();
 66     int m = 1 << k;
 67     for (int z = 0; z < m; ++z)
 68     {
 69         for (int i = 0; i < m; ++i)
 70         {
 71             if (lhs.mat[i][z] == 0) continue;
 72             for (int j = 0; j < m; ++j)
 73             {
 74                 ret2.mat[i][j] += lhs.mat[i][z] * rhs.mat[z][j];
 75                 if (ret2.mat[i][j] >= MOD)
 76                     ret2.mat[i][j] %= MOD;
 77             }
 78         }
 79     }
 80 }
 81 void pow(Matrix a, int t)
 82 {
 83     ret1.makeUnit();
 84     while (t)
 85     {
 86         if (t & 1)
 87         {
 88             multiply(ret1, a);
 89             copy(ret1, ret2);
 90         }
 91         t >>= 1;
 92         multiply(a, a);
 93         copy(a, ret2);
 94     }
 95 }
 96 bool check(int x, int y)
 97 {
 98     int m = 1 << k-1;
 99     while (m)
100     {
101         if ((x & 1) == 0 && (y & 1) == 1)
102         {
103             x >>= 1;
104             y >>= 1;
105             m >>= 1;
106         }
107         else if ((x & 1) == 1 && (y & 1) == 0)
108         {
109             x >>= 1;
110             y >>= 1;
111             m >>= 1;
112         }
113         else if ((x & 1) == 1 && (y & 1) == 1)
114         {
115             x >>= 1;
116             y >>= 1;
117             if ((x & 1) == 1 && (y & 1) == 1)
118             {
119                 x >>= 1;
120                 y >>= 1;
121                 m >>= 2;
122             }
123             else
124                 return false;
125         }
126         else
127             return false;
128     }
129     return true;
130 }
131 void makeMatrix()
132 {
133     int m = 1 << k;
134     for (int i = 0; i < m; ++i)
135     {
136         for (int j = 0; j < m; ++j)
137         {
138             if (check(i, j))
139                 a.mat[i][j] = 1;
140         }
141     }
142 }
143 int main()
144 {
145     scanf("%d%d", &k, &n);
146     a.makeZero();
147     //dfs(0, 0, 0);
148     makeMatrix();
149     pow(a, n);
150     int m = (1 << k) - 1;
151     printf("%d
", ret1.mat[m][m]);
152     return 0;
153 }
View Code
原文地址:https://www.cnblogs.com/justPassBy/p/4457802.html