描述
题解
第一次接触插头 dp ,感觉好厉害的说,详细的看了看 cdq 大佬的那个关于插头 dp 的 PPT ——《基于连通性状态压缩的动态规划问题》,算是对插头 dp 有了一丢丢的理解,然后再反过来看这个题依然是不会……
找了半天找到一个不错的题解,讲得虽然不算十分详细,但是如果看了上述的
PPT
后再看这个题解,应该是不难理解的,lastone’s blog 详细的解释了状态的转移以及在这里矩阵的用处,大佬们可以借鉴一下~~~另外需要指出的是,大佬的关于矩阵快速幂这里的解释是有些许的不清楚的,这里的
k
次是在利用矩阵快速幂时真正需要用到矩阵乘法的次数,知道矩阵快速幂的都不难理解,因为这里的
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int MAXN = 1 << 5;
ll dp[MAXN][MAXN];
ll ret[MAXN][MAXN];
ll tmp[MAXN][MAXN];
int m, n;
void dfs(int col, int pre, int now)
{
if (col > n)
{
return ;
}
if (col == n)
{
dp[pre][now]++;
return ;
}
dfs(col + 1, pre << 1, (now << 1) | 1);
dfs(col + 1, (pre << 1) | 1, now << 1);
dfs(col + 2, pre << 2 , now << 2);
}
void mul(ll ret[][MAXN], ll a[][MAXN], ll b[][MAXN])
{
int t = 1 << n;
for (int i = 0; i < t; i++)
{
for (int j = 0; j < t; j++)
{
ll tmp = 0;
for (int k = 0; k < t; k++)
{
tmp += a[i][k] * b[k][j];
tmp %= mod;
}
ret[i][j] = tmp;
}
}
}
int main()
{
scanf("%d%d", &m, &n);
dfs(0, 0, 0);
int t = 1 << n;
for (int i = 0; i < t; i++)
{
ret[i][i] = 1;
}
m++;
while (m)
{
for (int i = 0; i < t; i++)
{
for (int j = 0; j < t; j++)
{
tmp[i][j] = ret[i][j];
}
}
if (m & 1)
{
mul(ret, tmp, dp);
}
m = m >> 1;
mul(tmp, dp, dp);
for (int i = 0; i < t; i++)
{
for (int j = 0; j < t; j++)
{
dp[i][j] = tmp[i][j];
}
}
}
cout << ret[0][t - 1] << endl;
return 0;
}