宣传墙
时间限制:
1000 ms | 内存限制:
65535 KB
难度:
4
- 描述
-
ALPHA 小镇风景美丽,道路整齐,干净,到此旅游的游客特别多。CBA 镇长准备在一条道路南 面 4*N 的墙上做一系列的宣传。为了统一规划,CBA 镇长要求每个宣传栏只能占相邻的两个方格 位置。但这条道路被另一条道路分割成左右两段。CBA 镇长想知道,若每个位置都贴上宣传栏, 左右两段各有有多少种不同的张贴方案。 例如: N=6,M=3, K=2, 左,右边各有 5 种不同的张贴方案
- 输入
-
第一行: T 表示以下有 T 组测试数据 ( 1≤T ≤8 )
接下来有T行, 每行三个正整数 N M K 分别表示道路的长度,另一条道路的起点和宽度
(1≤ N ,M ≤ 1 000 000, 1≤ K ≤ 100000)
- 输出
-
每组测试数据,输出占一行:两个整数,分别表示左右两段不同的张贴方案数。由于方案总数
可能很大,请输出对 997 取模后的结果。 - 样例输入
-
2 6 3 2 5 3 2
- 样例输出
-
5 5 5 1
- 来源
矩阵快速幂解法,加判断数组,时间超短8ms,内存小8648
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MOD = 997; const int MAXN = 16; struct mat { int A[MAXN][MAXN]; mat() { memset(A, 0, sizeof(A)); } mat operator * (const mat &a) const { mat b; for (int i = 0; i < MAXN; i++) { for (int j = 0; j < MAXN; j++) { for (int k = 0; k < MAXN; k++) { b.A[i][j] += A[i][k] * a.A[k][j]; b.A[i][j] %= MOD; } } } return b; } }; mat map; bool cmp(int i, int j) // 状态 j 对状态 i 是否可行 j 是 col 列的状态 i 是 col - 1 列的状态 { for (int row = 0; row < 4; row++) { if ((i >> row) & 1) { if ((j >> row) & 1) { // if (row == 3) // 这个特判有没有都行,因为 i >> 4 肯定为 0 // { // 这样不过是思维更严谨些 // return false; // } if ((i >> (row + 1)) & 1) { i -= (1 << (row + 1)); // 等价于 i ^= 1 << (rank + 1),前边的写法不太直观 } else { return false; } } else { continue; } } else { if ((j >> row) & 1) { continue; } else { return false; } } } return true; } // 构造单元矩阵 void unit() { for (int i = 0; i < MAXN; i++) { for (int j = 0; j < MAXN; j++) { map.A[i][j] = cmp(i, j); } } } int slove(int n) { mat a; mat b = map; for (int i = 0; i < MAXN; i++) { a.A[i][i] = 1; } while (n) { if (n & 1) { a = a * b; } b = b * b; n >>= 1; } return a.A[MAXN - 1][MAXN - 1]; } int main () { int T; scanf("%d", &T); unit(); while (T--) { int N, M, K; scanf("%d%d%d", &N, &M, &K); printf("%d %d\n", slove(M - 1), slove(N - M - K + 1)); } return 0; }
状态压缩 DP
滚动数组解法 时间长713ms,内存大 94896
#include <stdio.h> #include <string.h> #include <stdlib.h> const int col = 4; int row; int dp[900000][1<<4]; void dfs(int r,int c,int pre,int now) { if(c==col) { dp[r][now] += dp[r-1][pre]; dp[r][now] %= 997; return ; } if(c+1<=col) { dfs(r,c+1,pre<<1,(now<<1)|1); dfs(r,c+1,(pre<<1)|1 ,now<<1); } if(c+2<=col) { dfs(r,c+2,(pre<<2)|3,(now<<2)|3); } } int main() { int T,N,M,K; scanf("%d",&T); while(T--) { scanf("%d%d%d",&N,&M,&K); row = M - 1; if(row<=0) { printf("0 "); } else { memset(dp,0,sizeof(dp)); dp[0][(1<<col)-1] = 1; for(int i=1;i<=row;i++) { dfs(i,0,0,0); } printf("%d ",dp[row][(1<<col)-1]); } row = N - M - K + 1; if(row<=0) { printf("0\n"); } else { memset(dp,0,sizeof(dp)); dp[0][(1<<col)-1] = 1; for(int i=1;i<=row;i++) { dfs(i,0,0,0); } printf("%d\n",dp[row][(1<<col)-1]); } } return 0; }