# Description
Luogu 传送门
说实话我感觉这题说的还挺迷的,看了好久题意才看懂 QwQ
这里稍微解释一下吧,就是初始的时候给你一个字符矩阵,上面有黑白两种格子,保证黑格子四联通。
然后你需要扩展这个字符矩阵。
简单来说,假设当前矩阵为 级矩阵,要扩展成 级矩阵,我们把黑格子变成当前字符矩阵( 级矩阵)的样子,白格子就变成当前字符矩阵大小的全白格子。
这是样例一的 2 级分形:
...|.#.|... | |
...|###|... | |
...|#.#|... | |
----------- | |
.#.|.#.|.#. | |
###|###|### | |
#.#|#.#|#.# | |
----------- | |
.#.|...|.#. | |
###|...|### | |
#.#|...|#.# |
最后计算 级分形的黑色格子连通块个数
# Solution
我们要考虑一下每次扩展之后会多出来哪些黑色连通块,又有哪些黑色连通块会彼此连在一起。
分类讨论:
扩展时上下左右都会相连,答案显然就是 1。
扩展时上下左右都不会相连,答案就是 。
上下或左右相连,我们以样例一为例好好分析一下(图见上)。
样例一属于左右会相连,上下不相连的情况。
连通块个数从 1 变为了 4。
简单推一下规律,不难发现:
然后我们再扩展一次,发现这个结论还是对的!
那么这个东西如何计算呢?
设 表示黑色格子个数, 表示总的相邻黑点对数, 表示拼接时两个相邻的大块之间形成的黑色点对数。
第一条式子和第三条式子应该不难理解吧。
第二条:原本有的相邻黑点对数在所有黑点扩展出的图形中都会出现一遍(),然后再加上边界上出现的次数( 这个可以手推一下)。
于是我们就得到了递推式子。
不难发现,这东西可以矩阵快速幂优化一下。矩阵长这个样子:
快速幂计算它的 次方即可。
# Code
#include <bits/stdc++.h> | |
#define ll long long | |
using namespace std; | |
const int N = 1010; | |
const int mod = 1e9 + 7; | |
int n, m; | |
ll k; | |
char t[N]; | |
int s[N][N]; | |
inline int qpow(int a, ll b){ | |
int res = 1; | |
while(b){ | |
if(b & 1) res = 1ll * res * a % mod; | |
a = 1ll * a * a % mod, b >>= 1; | |
} | |
return res; | |
} | |
/* | |
|a,b| | |
|0,c| | |
*/ | |
struct matrix{ | |
int a, b, c; | |
matrix(int _a = 0, int _b = 0, int _c = 0) {a = _a, b = _b, c = _c;} | |
friend matrix operator * (matrix A, matrix B){ | |
matrix C; | |
C.a = 1ll * A.a * B.a % mod; | |
C.b = (1ll * A.a * B.b + 1ll * A.b * B.c) % mod; | |
C.c = 1ll * A.c * B.c % mod; | |
return C; | |
} | |
matrix operator ^ (ll p) const{ | |
matrix r(1, 0, 1), B(a, b, c); | |
for(; p; B = B * B, p >>= 1) | |
if(p & 1) r = r * B; | |
return r; | |
} | |
}f; | |
int main(){ | |
scanf("%d%d%lld", &n, &m, &k); | |
if(!k) return puts("1"), 0; | |
for(int i = 1; i <= n; ++i){ | |
scanf("%s", t + 1); | |
for(int j = 1; j <= m; ++j) | |
s[i][j] = (t[j] == '#'); | |
} | |
int cnt = 0, ud = 0, lr = 0, UD = 0, LR = 0; | |
for(int i = 1; i <= n; ++i) | |
for(int j = 1; j <= m; ++j){ | |
cnt += s[i][j]; | |
if(i == 1) UD += s[1][j] & s[n][j]; | |
else ud += s[i][j] & s[i - 1][j]; | |
if(j == 1) LR += s[i][1] & s[i][m]; | |
else lr += s[i][j] & s[i][j - 1]; | |
} | |
if(!UD && !LR) printf("%d\n", qpow(cnt, k - 1)); | |
else if(UD && LR) puts("1"); | |
else{ | |
if(UD) f = matrix(cnt, ud, UD) ^ (k - 1); | |
else f = matrix(cnt, lr, LR) ^ (k - 1); | |
printf("%d\n", (f.a - f.b + mod) % mod); | |
} | |
return 0; | |
} |