[??记录]AT2006 [AGC003F] Fraction of Fractal

command_block

2021-04-21 11:37:49

Personal

**题意** : 给出一张 $n\times m$ 的黑白点阵。定义其为初始图。 定义 $0$ 级分型为单独一个黑格。 定义 $k$ 级分型 : 将初始图的每个黑格替换为 $k-1$ 级分型,而将白格替换为纯白的,和 $k-1$ 级分型同样大小的区域。 求 $k$ 级分型中黑格形成的四联通块个数,答案对 $10^9+7$ 取模。 保证 $1$ 级分型中的黑格四连通。 $n,m\leq 10^3,k\leq 10^{18}$ ,时限 $\texttt{2s}$。 ------------ - 初始图上下连通,左右也连通。 答案是 $1$。 - 初始图上下不连通,左右也不连通。 设 $c$ 为初始图中的黑格个数,答案是 $c^{k-1}$。 - 初始图仅上下连通或仅左右连通。 考虑仅上下联通的情况,另一种情况只需翻转初始图。 此时,只有上下两个相邻的初始图之间可能联通,以初始图为单元,边集为森林(若干条竖链)。 于是,联通块个数等于点数减边数,即 $c^{k-1}-$ 上下相邻的初始图对数。 记 $a$ 为初始图中上下相邻的黑格对数,$b$ 为跨越上下边界的相邻的黑格对数。 对于 $k$ 级分型,记 $a_k$ 为分型中上下相邻的初始图对数, $b_k$ 为跨越上下边界相邻的初始图对数,$c_k$ 为含有的初始图数目。 则有如下递推关系 : $$ \begin{aligned} a_k&=a_{k-1}*c+b_{k-1}*a\\ b_k&=b_{k-1}*b\\ c_k&=c_{k-1}*c\\ \end{aligned} $$ 不难用矩阵快速幂加速计算。 ```cpp #include<algorithm> #include<cstdio> #define ll long long #define MaxN 1050 using namespace std; const int mod=1000000007; ll powM(ll a,ll t){ ll ret=1; while(t){ if (t&1)ret=ret*a%mod; a=a*a%mod;t>>=1; }return ret; } struct Matrix{ ll a[3][3]; void I(){ for (int i=0;i<3;i++) for (int j=0;j<3;j++) a[i][j]=(i==j); } }; Matrix operator * (const Matrix &A,const Matrix &B) { Matrix C; for (int i=0;i<3;i++) for (int j=0;j<3;j++){ C.a[i][j]=0; for (int k=0;k<3;k++) C.a[i][j]=(C.a[i][j]+A.a[i][k]*B.a[k][j])%mod; } return C; } Matrix powM(Matrix A,ll t){ Matrix R;R.I(); while(t){ if (t&1)R=R*A; A=A*A;t>>=1; }return R; } ll calc(int a,int b,int c,ll k) { Matrix A; A.a[0][0]=c;A.a[1][0]=a;A.a[2][0]=0; A.a[0][1]=0;A.a[1][1]=b;A.a[2][1]=0; A.a[0][2]=0;A.a[1][2]=0;A.a[2][2]=c; A=powM(A,k-1); return (A.a[1][0]+A.a[2][0])%mod; } int n,m;long long k; char s[MaxN][MaxN]; int main() { scanf("%d%d%lld",&n,&m,&k); if (k<=1){puts("1");return 0;} for (int i=1;i<=n;i++) scanf("%s",s[i]+1); int b1=0,b2=0,c=0; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) c+=s[i][j]=='#'; for (int i=1;i<=n;i++) b1+=s[i][1]=='#'&&s[i][m]=='#'; for (int j=1;j<=m;j++) b2+=s[1][j]=='#'&&s[n][j]=='#'; if (!b1&&!b2){printf("%lld",powM(c,k-1));return 0;} if (b1&&b2){puts("1");return 0;} int a=0; if (b1){ for (int i=1;i<=n;i++) for (int j=1;j<m;j++) a+=s[i][j]=='#'&&s[i][j+1]=='#'; printf("%lld",(powM(c,k-1)-calc(a,b1,c,k)+mod)%mod); }else { for (int i=1;i<n;i++) for (int j=1;j<=m;j++) a+=s[i][j]=='#'&&s[i+1][j]=='#'; printf("%lld",(powM(c,k-1)-calc(a,b2,c,k)+mod)%mod); }return 0; } ```