赞
踩
标题:铺瓷砖
为了让蓝桥杯竞赛更顺利的进行,主办方决定给竞赛的机房重新铺放瓷砖。机房可以看成一个n*m的矩形,而这次使用的瓷砖比较特别,有两种形状,如【图1.png】所示。在铺放瓷砖时,可以旋转。
主办方想知道,如果使用这两种瓷砖把机房铺满,有多少种方案。
【输入格式】
输入的第一行包含两个整数,分别表示机房两个方向的长度。
【输出格式】
输出一个整数,表示可行的方案数。这个数可能很大,请输出这个数除以65521的余数。
【样例输入1】
4 4
【样例输出1】
2
【样例说明1】
这两种方案如下【图2.png】所示:
【样例输入2】
2 6
【样例输出2】
4
【数据规模与约定】
对于20%的数据,1<=n, m<=5。
对于50%的数据,1<=n<=100,1<=m<=5。
对于100%的数据,1<=n<=10^15,1<=m<=6。
资源约定:
峰值内存消耗(含虚拟机) < 512M
CPU消耗 < 8000ms
求解使用两种瓷砖铺满一个n*m的区域的方案数。
对于小范围的数据,可以使用搜索求解。也可以使用搜索在自己的电脑上先算出方案数,将这些答案保存在程序中,直接输出答案即可。
对于稍微大一点的数据,可以使用状态压缩的动态规划来求解。有两种瓷砖,状态的转移比较复杂,
对于100%的数据,需要将在状态压缩的动态规划中去除无用状态,然后建立矩阵表示,使用矩阵乘法的方法来实现状态压缩中的递推。
- //瓷砖铺放
- #include <iostream>
- #include <cstdlib>
- #include <cstdio>
- #include <cstring>
- using namespace std;
-
- const int MOD = 65521;
-
- const int MM = 800;
- const int RSIZE = 128;
-
- const int MATRIX_SIZE = 256;
-
- class Matrix {
- public:
- unsigned int s[MATRIX_SIZE][MATRIX_SIZE];
- };
-
- long long n;
- int m, M;
- int tt[MM][RSIZE], fr[MM][RSIZE];
- int *cur[MM], *curFr[MM];
- int tc[MM], nc[MM];
- Matrix tm, dst, tmpm;
- bool mark[MM], canReach[MM];
- int remap[MM], who[MM];
-
- void search(int cp, int cl, int nl)
- {
- if (cp > m)
- return ;
- if (cp == m)
- {
- *(cur[cl]++) = nl;
- *(curFr[nl]++) = cl;
- return ;
- }
- search(cp+1, cl*3+1, nl*3);
- search(cp+1, cl*3+2, nl*3+1);
-
- // (1)
- search(cp+2, cl*3*3+1, nl*3*3+3+1);
- search(cp+3, cl*3*3*3, nl*3*3*3+9+3+1);
- search(cp+4, cl*3*3*3*3, nl*3*3*3*3+27+9+3);
- // (2)
- search(cp+2, cl*3*3, nl*3*3+1);
- // (3)
- search(cp+2, cl*3*3, nl*3*3+3);
- // (4)
- if (cp>0 && nl%3==0)
- search(cp+1, cl*3, nl*3+3+1);
- // (5)
- search(cp+2, cl*3*3+1, nl*3*3+3*2+1);
- search(cp+3, cl*3*3*3, nl*3*3*3+9*2+3+1);
- search(cp+4, cl*3*3*3*3, nl*3*3*3*3+27*2+9+3);
- // (6)
- search(cp+3, cl*3*3*3, nl*3*3*3+3);
- // (7)
- if (cp>0 && nl%3==0)
- search(cp+1, cl*3, nl*3+3+2);
- // (8)
- if (cp>0 && nl%3==0)
- {
- search(cp+2, cl*3*3+1, nl*3*3+9+3+1);
- search(cp+3, cl*3*3*3, nl*3*3*3+27+9+3+1);
- search(cp+4, cl*3*3*3*3, nl*3*3*3*3+81+27*2+9+3);
- }
- }
- void goto0(int x)
- {
- if (canReach[x])
- return ;
- canReach[x] = true;
- for (int *pp = fr[x]; pp < curFr[x]; ++pp)
- goto0(*pp);
- }
-
- int ccnt = 0;
- void go(int x)
- {
- if (!canReach[x])
- return ;
- if (mark[x])
- return ;
- who[ccnt] = x;
- remap[x] = ccnt++;
- mark[x] = true;
- for (int *pp = tt[x]; pp < cur[x]; ++pp)
- go(*pp);
- }
- void pr3(int x, int w)
- {
- if (w > 1)
- pr3(x/3, w-1);
- cout << x%3;
- }
- void prepare()
- {
- memset(tt, 0, sizeof(tt));
- for (int i = 0; i < M; ++i)
- {
- cur[i] = tt[i];
- curFr[i] = fr[i];
- }
- search(0, 0, 0);
-
- int maxR = 0;
- for (int i = 0; i < M; ++i)
- if (cur[i]-tt[i] > maxR)
- maxR = cur[i] - tt[i];
-
- maxR = 0;
- for (int i = 0; i < M; ++i)
- if (curFr[i]-fr[i] > maxR)
- maxR = curFr[i] - fr[i];
-
- memset(canReach, 0, sizeof(canReach));
- goto0(0);
-
- memset(mark, 0, sizeof(mark));
- go(0);
-
- memset(&tm, 0, sizeof(tm));
- for (int i = 0; i < M; ++i)
- if (mark[i])
- for (int *pp = tt[i]; pp < cur[i]; ++pp)
- if (mark[*pp])
- tm.s[remap[i]][remap[*pp]]++;
- }
- void matrixMul(Matrix &dst, const Matrix &a, const Matrix &b)
- {
- for (int i = 0; i < ccnt; ++i)
- for (int j = 0; j < ccnt; ++j)
- {
- long long r = 0;
- const unsigned int *ai = a.s[i];
- for (int k = 0; k < ccnt; ++k)
- r += ai[k] * b.s[k][j];
- r %= MOD;
- dst.s[i][j] = r;
- }
- }
- long long getAns()
- {
- long long cur = 1;
- memset(&dst, 0, sizeof(dst));
- for (int i = 0; i < ccnt; ++i)
- dst.s[i][i] = 1;
- while (n)
- {
- if (n&cur)
- {
- matrixMul(tmpm, dst, tm);
- dst = tmpm;
- n -= cur;
- }
- matrixMul(tmpm, tm, tm);
- tm = tmpm;
- cur *= 2;
- }
- return dst.s[0][0];
- }
- int main()
- {
- cin >> n >> m;
- M = 1;
- for (int i = 0; i < m; ++i)
- M *= 3;
- prepare();
- cout << getAns() << endl;
- return 0;
- }
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。