从这篇博客学到很多:
直接枚举高的状态,一旦此状态确定了,之后的状态就都确定了。
poj2411:
题意:
给定一个长宽小于等于11的矩形,问用1×2的小矩形填满,有多少种方法。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 12;
int h, w;
LL dp[maxn][1 << maxn];
vector<pair<int, int> > path;
void dfs(int dep, int nowState, int preState)
{
if (dep > w)
return;
if (dep == w)
{
path.push_back(make_pair(nowState, preState));
return;
}
dfs(dep + 2, (nowState << 2) | 3, (preState << 2) | 3);
dfs(dep + 1, (nowState << 1) | 1, preState << 1);
dfs(dep + 1, nowState << 1, (preState << 1) | 1);
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
while (~scanf("%d%d", &h, &w))
{
if (!h && !w)
break;
if (h < w)
swap(h, w);
path.clear();
dfs(0, 0, 0);
memset(dp, 0, sizeof(dp));
dp[0][(1 << w) - 1] = 1;
for (int i = 1; i <= h; i++)
{
for (int j = 0; j < path.size(); j++)
{
int now = path[j].first;
int pre = path[j].second;
dp[i][now] += dp[i - 1][pre];
}
}
printf("%lld\n", dp[h][(1 << w) - 1]);
}
return 0;
}
poj 2663:
题意:
给定1*2的小矩形,去拼接一个3*n(n<30)的矩形,问有多少种方案。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1
using namespace std;
const int inf = 0x3f3f3f3f;
typedef vector<LL> vec;
typedef vector<vec> mat;
int h, w;
mat A(20, vec(20));
void dfs(int dep, int nowState, int preState)
{
if (dep > w)
return;
if (dep == w)
{
A[preState][nowState]++;
return;
}
dfs(dep + 2, (nowState << 2) | 3, (preState << 2) | 3);
dfs(dep + 1, (nowState << 1) | 1, preState << 1);
dfs(dep + 1, nowState << 1, (preState << 1) | 1);
}
mat mul(mat &A, mat &B)
{
mat C(A.size(), vec(B[0].size()));
for (int i = 0; i < A.size(); i++)
{
for (int k = 0; k < B.size(); k++)
{
for (int j = 0; j < B[0].size(); j++)
{
// C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % mod;
C[i][j] = (C[i][j] + A[i][k] * B[k][j]);
}
}
}
return C;
}
mat pow(mat A, LL n)
{
mat B(A.size(), vec(A.size()));
for (int i = 0; i < A.size(); i++)
{
B[i][i] = 1;
}
while (0 < n)
{
if (n & 1)
B = mul(B, A);
A = mul(A, A);
n >>= 1;
}
return B;
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
w = 3;
dfs(0, 0, 0);
while (~scanf("%d", &h))
{
if (h == -1)
break;
mat ans = pow(A, h);
printf("%lld\n", ans[(1 << w) - 1][(1 << w) - 1]);
}
return 0;
}
poj 2420:
题意:
给定1*2的小矩形,去拼接一个4*n(n<10^9)的矩形,问有多少种方案。
解析:
N这么大递推肯定是不行了,所以我们要用矩阵快速幂进行加速,这个转移矩阵如何构造呢,我们可以直接用pre状态转移到now状态采用邻接矩阵的方式表述就好了。这个矩阵的大小为at[16][16],at[15][15]就是最后要求的状态。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1
using namespace std;
const int inf = 0x3f3f3f3f;
typedef vector<LL> vec;
typedef vector<vec> mat;
int h, w;
int mod;
mat A(20, vec(20));
void dfs(int dep, int nowState, int preState)
{
if (dep > w)
return;
if (dep == w)
{
A[preState][nowState]++;
return;
}
dfs(dep + 2, (nowState << 2) | 3, (preState << 2) | 3);
dfs(dep + 1, (nowState << 1) | 1, preState << 1);
dfs(dep + 1, nowState << 1, (preState << 1) | 1);
}
mat mul(mat &A, mat &B)
{
mat C(A.size(), vec(B[0].size()));
for (int i = 0; i < A.size(); i++)
{
for (int k = 0; k < B.size(); k++)
{
for (int j = 0; j < B[0].size(); j++)
{
C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % mod;
// C[i][j] = (C[i][j] + A[i][k] * B[k][j]);
}
}
}
return C;
}
mat pow(mat A, LL n)
{
mat B(A.size(), vec(A.size()));
for (int i = 0; i < A.size(); i++)
{
B[i][i] = 1;
}
while (0 < n)
{
if (n & 1)
B = mul(B, A);
A = mul(A, A);
n >>= 1;
}
return B;
}
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
w = 4;
dfs(0, 0, 0);
while (~scanf("%d%d", &h, &mod))
{
if (!h && !mod)
break;
mat ans = pow(A, h);
printf("%lld\n", ans[(1 << w) - 1][(1 << w) - 1]);
}
return 0;
}