hihoCoder #1151 : 骨牌覆盖问题·二 (矩阵快速幂,DP)

题意:给一个3*n的矩阵,要求用1*2的骨牌来填满,有多少种方案?

思路:

  官网题解用的仍然是矩阵快速幂的方式。复杂度O(logn*83)。

  这样做需要构造一个23*23的矩阵,这个矩阵自乘n-1次,再来乘以初始矩阵init{0,0,0,0,0,0,0,1}后,变成矩阵ans{x,x,x,x,x,x,x,y},y就是答案了,而x不必管。

  主要在这个矩阵的构造,假设棋盘是放竖直的(即n*3),那么考虑在第i行进行填放,需要考虑到第i-1行的所有可能的状态(注意i-2行必须是已经填满了,否则第i行无法填到i-2行去)。放的时候有个规则,就是所放的每块1*2的骨牌,必须放有一半以上是在第i行的,而且不允许放到第i+1行去。其实就是根据3种选择来考虑变换,(1)不放(2)放横(3)放竖。

  下图假设即将填第i+1行。

  上图的编号代表了第i行的状态。

  上图就是从第i行可以转移到第i+1行的状态。matrix[i][j]表示第i行的状态i转移到第i+1行的状态j的方案数,空格为0。

  举个例子:第i行的状态为3,那么它只放一块骨牌时(即填满右上角的一个空格),转为4。如果放两块(即在4的基础上再放一块横的),就转为7。

  上面只需要特别注意所假设的东西,而且要按照规则来放才行。

 1 #include <bits/stdc++.h>
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #define pii pair<int,int>
 6 #define INF 0x3f3f3f3f
 7 #define LL long long
 8 using namespace std;
 9 const int N=1e5+2;
10 const int mod=12357;
11 int M[8][8]={0,0,0,0,0,0,0,1,
12              0,0,0,0,0,0,1,0,
13              0,0,0,0,0,1,0,0,
14              0,0,0,0,1,0,0,1,
15              0,0,0,1,0,0,0,0,
16              0,0,1,0,0,0,0,0,
17              0,1,0,0,0,0,0,1,
18              1,0,0,1,0,0,1,0};  //初始矩阵M
19
20 int init[8]={0,0,0,0,0,0,0,1};  //初始状态
21 int tot[8][8], cur[8][8], grid[8][8];   //临时的矩阵
22
23 void mul(int A[][8],int B[][8]) //处理两个8*8的矩阵相乘,并保存到A中
24 {
25     for(int i=0; i<8; i++)
26     {
27         for(int j=0; j<8; j++)
28         {
29             int tmp=0;
30             for(int k=0; k<8; k++)
31             {
32                 tmp+=A[i][k]*B[k][j];
33                 tmp%=mod;
34             }
35             grid[i][j]=tmp;
36         }
37     }
38     memcpy(A, grid, sizeof(grid));
39 }
40
41
42 int cal(int n)
43 {
44     memcpy(tot, M, sizeof(M));
45     memcpy(cur, M, sizeof(M));
46     n--;    //tot已经是2^0了,所以自减1.
47     while(n)
48     {
49         if(n&1==1)    mul(tot, cur);   //末位为1时,累乘到tot中
50         mul(cur, cur);                 //翻倍
51         n>>=1;
52     }
53     for(int i=0,tmp=0; i<8; i++,tmp=0)  //最后两个矩阵
54     {
55         for(int j=0; j<8; j++)
56         {
57             tmp+=tot[i][j]*init[j];
58             tmp%=mod;
59         }
60         grid[0][i]=tmp;
61     }
62     return grid[0][7];
63 }
64
65 int main()
66 {
67     //freopen("input.txt", "r", stdin);
68     int n;
69     while(~scanf("%d",&n))    printf("%d\n", cal(n));
70     return 0;
71 }

AC代码

  还有一种方案仅需0ms。即递推,这个需要研究一下递推式,考虑各种情况的变化。不写了。

时间: 2024-07-30 10:17:53

hihoCoder #1151 : 骨牌覆盖问题·二 (矩阵快速幂,DP)的相关文章

hihocoder 1151 骨牌覆盖问题 二 (矩阵快速幂)

思路见hihocoder,用的kuangbin的矩阵快速幂,一次AC,6的一笔. #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <string> #include <stack> #include <cmath> #include <queue> #include <set>

hihoCode #1151 : 骨牌覆盖问题&#183;二

#1151 : 骨牌覆盖问题·二 Time Limit:10000ms Case Time Limit:1000ms Memory Limit:256MB 描述 上一周我们研究了2xN的骨牌问题,这一周我们不妨加大一下难度,研究一下3xN的骨牌问题?所以我们的题目是:对于3xN的棋盘,使用1x2的骨牌去覆盖一共有多少种不同的覆盖方法呢?首先我们可以肯定,奇数长度一定是没有办法覆盖的:对于偶数长度,比如2,4,我们有下面几种覆盖方式: 提示:3xN骨牌覆盖 输入 第1行:1个整数N.表示棋盘长度.

bnu 34985 Elegant String(矩阵快速幂+dp推导公式)

Elegant String Time Limit: 1000ms Memory Limit: 65536KB 64-bit integer IO format: %lld      Java class name: Main Prev Submit Status Statistics Discuss Next Type: None None Graph Theory      2-SAT     Articulation/Bridge/Biconnected Component      Cy

VOJ 1067 Warcraft III 守望者的烦恼 (矩阵快速幂+dp)

题目链接 显然可知 dp[n] = dp[n-k] + dp[n-k+1] + ... +dp[n-1]; 然后要用矩阵来优化后面的状态转移. 也就是矩阵 0 1 0 0    a     b 0 0 1 0 * b =  c 0 0 0 1    c     d 1 1 1 1    d    a+b+c+d 然后跑快速幂 #include <iostream> #include <cstdio> #include <algorithm> #include <c

hihoCoder#1743:K-偏差排列(矩阵快速幂+状压dp)

题意: 如果一个 \(1\to N\) 的排列 \(P=[P_1, P_2, ... P_N]\) 中的任意元素 \(P_i\) 都满足 \(|P_i-i| ≤ K\) ,我们就称 \(P\) 是 \(K\)-偏差排列. 给定 \(N\) 和 \(K\) ,请你计算一共有少个不同的排列是 \(K\)-偏差排列. 例如对于 \(N=3\) ,有 \(3\) 个 \(1\)-偏差排列:\([1, 2, 3], [1, 3, 2], [2, 1, 3]\). 由于答案可能非常大,你只需要输出答案模 \

COJ 1208 矩阵快速幂DP

题目大意: f(i) 是一个斐波那契数列 , 求sum(f(i)^k)的总和 由于n极大,所以考虑矩阵快速幂加速 我们要求解最后的sum[n] 首先我们需要思考 sum[n] = sum[n-1] + f(i+1)^k 那么很显然sum[n-1]是矩阵中的一个元素块 那么f(i+1)^k怎么利用f(i) , f(i-1)来求 f(i+1)^k = (f(i) + f(i-1)) ^ k 假如k = 1 , 可以看出f(i+1) = f(i-1) + f(i) (1,1) k = 2 , 可以看出

Codeforces 576D Flights for Regular Customers 矩阵快速幂+DP

题意: 给一个\(n\)点\(m\)边的连通图 每个边有一个权值\(d\) 当且仅当当前走过的步数\(\ge d\)时 才可以走这条边 问从节点\(1\)到节点\(n\)的最短路 好神的一道题 直接写做法喽 首先我们对边按\(d_i\)由小到大排序 设\(f_i\)表示加上\(1\sim i-1\)的所有边走\(d_i\)次后各点间的联通情况 \(G\)表示只连\(1\sim i-1\)的边的邻接矩阵 这些我们可以用一个\(01\)邻接矩阵来存储 则有 \(f_i=f_{i-1}*G^{d_i-

P1357 花园 (矩阵快速幂+ DP)

题意:一个只含字母C和P的环形串 求长度为n且每m个连续字符不含有超过k个C的方案数 m <= 5  n <= 1e15 题解:用一个m位二进制表示状态 转移很好想 但是这个题是用矩阵快速幂加速dp的 因为每一位的转移都是一样的 用一个矩阵表示状态i能否转移到状态j 然后跑一遍 初试模板题 #include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod = 1e9 + 7; ll n,

hihoCoder 1143 : 骨牌覆盖问题&#183;一(递推,矩阵快速幂)

[题目链接]:click here~~ 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 骨牌,一种古老的玩具.今天我们要研究的是骨牌的覆盖问题: 我们有一个2xN的长条形棋盘,然后用1x2的骨牌去覆盖整个棋盘.对于这个棋盘,一共有多少种不同的覆盖方法呢? 举个例子,对于长度为1到3的棋盘,我们有下面几种覆盖方式: 提示:骨牌覆盖 提示:如何快速计算结果 输入 第1行:1个整数N.表示棋盘长度.1≤N≤100,000,000 输出 第1行:1个整数,表示覆盖方案数 M