51Nod-1033-骨牌覆盖 V2

来源:互联网 发布:软件测试英文简历 编辑:程序博客网 时间:2024/05/19 12:16

ACM模版

描述

描述

题解

第一次接触插头 dp,感觉好厉害的说,详细的看了看 cdq 大佬的那个关于插头 dpPPT——《基于连通性状态压缩的动态规划问题》,算是对插头 dp 有了一丢丢的理解,然后再反过来看这个题依然是不会……

找了半天找到一个不错的题解,讲得虽然不算十分详细,但是如果看了上述的 PPT 后再看这个题解,应该是不难理解的,lastone’s blog 详细的解释了状态的转移以及在这里矩阵的用处,大佬们可以借鉴一下~~~另外需要指出的是,大佬的关于矩阵快速幂这里的解释是有些许的不清楚的,这里的 k 次是在利用矩阵快速幂时真正需要用到矩阵乘法的次数,知道矩阵快速幂的都不难理解,因为这里的 m 太大了,如果不用快速幂搞肯定会超时的。

代码

#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;}
原创粉丝点击