hihor 学习日记:hiho一下 第四十二周 (快速幂+状压)

http://hihocoder.com/contest/hiho42/problems

题意:

求一个3xN的矩形有1x2的骨牌覆盖有多少种方法

思路:

咋一看有点像轮廓线dp,但是因为N的范围太大,若果使用O(n)的算法会超时,所以可以观察矩形,
与轮廓线类似,假设使用dp,是从左到右,从上到下,那么对于第i行,那么前面的i-1行就都已经dp完毕
比如这么一个矩形,前面绿色的是已经dp完毕的,蓝色是现在正在进行的。
在这里插入图片描述
有轮廓线dp可知,蓝色的数量跟黄色是密切相关的,
如果用0表示未填充,1表示已填充,那么有黄色的状态可有 2 3 2^3 种,从0–>7,
那么其状态的对应关系就为:
详解可以看轮廓线dp:https://blog.csdn.net/henu_jizhideqingwa/article/details/83932874
注意,这里对蓝色的填充不可涉及到后面的部分,比如黄色为7时,蓝色的1全是上下的,而不是左右的。
7:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6:
在这里插入图片描述
在这里插入图片描述

5:
在这里插入图片描述
4:
在这里插入图片描述
3:
在这里插入图片描述
在这里插入图片描述
2:
在这里插入图片描述
1:
在这里插入图片描述
0:
在这里插入图片描述

那么对应这个图我们可以做出一个表
在这里插入图片描述
这个图可以看成一个矩阵,矩阵相乘就是总的方案数,但是对于第一行我们缺少一个黄色区域的状态,但是我们很容易想到这个黄色区域的状态应该为7,所以我们现在有了几个已知的变量,A(起点的黄色部分), M(得出的8X8矩阵), N
N(要求的矩阵的长)
那么结果就为 A M N A * M^N , 这时我们得到的是一个1XN的矩阵,
得到的是矩阵末尾列的状态的数值,理所当然我们应该得到的是状态为7的值

AC代码:

#include <bits/stdc++.h>

using namespace std;
#define LL long long
const int Mod = 12357;
const int maxn = 1e5 + 5;
const double eps = 0.00000001;
const int INF = 0x3f3f3f3f;

struct Adj{
    int a[8][8];

    Adj friend operator * (Adj a, Adj b) {
        Adj c;
        memset(c.a, 0, sizeof(c.a));
        for (int i = 0; i < 8; i ++)
            for (int j = 0; j < 8; j ++)
                for (int k = 0; k < 8; k ++)
                    c.a[i][j] = (c.a[i][j] + a.a[i][k] * b.a[k][j] % Mod) % Mod;
        return c;
    }
};

Adj QuickPow(Adj a, int b) {
    Adj ans = {1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
    Adj base = a;
    while(b) {
        if(b & 1) ans = ans * base;
        base = base * base;
        b >>= 1;
    }
    return ans;
}

int main()
{
    Adj a, b, c;
    a = Adj{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
    b = Adj{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0,};
    int N;
    cin >> N;
    c = QuickPow(b, N);
    a = a * c;
    cout << a.a[0][7] << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/henu_jizhideqingwa/article/details/84932377