[矩阵快速幂] Atcoder AGC003 F. Fraction of Fractal

来源:互联网 发布:网络21 编辑:程序博客网 时间:2024/05/29 09:39

很神的题!!!

首先观察一下每次转移

如果初始的图案存在某一行 i,满足行的两个端点为黑,且存在某一列也是满足这样的条件,那么答案就是1,因为原来就连通的黑块转移后的图案也是联通的。

如果行和列都不满足,因为每次转移答案都会乘 x, 那么答案就是 xk1 ,其中 x 为初始图案中的黑块数量。

如果只有行满足这样的条件(列满足的话转一下图案),

x 等于黑块的数量, y 等于初始图像中 ai,jai,j+1 都为黑的 (i,j) 数量, z 为几行满足上面的条件

那么每次转移就有

  • x=x2
  • y=xy+yz
  • z=z2

这个东西退一下可以知道…

用矩阵转移就好了…

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <assert.h>using namespace std;typedef long long ll;const int N=1010,P=1e9+7;struct mat{  int a[2][2];  mat(){ a[0][0]=a[1][1]=a[0][1]=a[1][0]=0; }  int *operator [](int x){    return a[x];  }  friend mat operator *(mat a,mat b){    mat c;    c[0][0]=(1LL*a[0][0]*b[0][0]+1LL*a[0][1]*b[1][0])%P;    c[0][1]=(1LL*a[0][0]*b[0][1]+1LL*a[0][1]*b[1][1])%P;    c[1][0]=(1LL*a[1][0]*b[0][0]+1LL*a[1][1]*b[1][0])%P;    c[1][1]=(1LL*a[1][0]*b[0][1]+1LL*a[1][1]*b[1][1])%P;    return c;  }};mat u;int n,m;char a[N][N],b[N][N];ll k;inline int judge(){  for(int i=1;i<=n;i++)    if(a[i][1]=='#' && a[i][m]=='#') return 1;  return 0;}inline void turn(){  for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++)      b[m-j+1][i]=a[i][j];  swap(n,m); memcpy(a,b,sizeof(a));}inline int Pow(int x,ll y){  int ret=1;  for(;y;y>>=1,x=1LL*x*x%P) if(y&1) ret=1LL*ret*x%P;  return ret;}inline mat Pow(mat x,ll y){  mat ret=u;  for(;y;y>>=1,x=x*x) if(y&1) ret=ret*x;  return ret;}int main(){  freopen("1.in","r",stdin);  freopen("1.out","w",stdout);  u[0][0]=u[1][1]=1;  scanf("%d%d%lld",&n,&m,&k);  int cnt=0;  for(int i=1;i<=n;i++){    scanf("%s",a[i]+1);    for(int j=1;j<=m;j++)      cnt+=a[i][j]=='#';  }  int A=judge(),B=(turn(),judge()); turn();  if((A && B) || !k) return puts("1"),0;  if(!A && !B) return printf("%d\n",Pow(cnt,k-1)),0;  if(!A) turn();  int c=0,b=0; for(int i=1;i<=n;i++) c+=(a[i][1]=='#' && a[i][m]=='#');  for(int i=1;i<=n;i++)    for(int j=1;j<m;j++)      b+=(a[i][j]=='#' && a[i][j+1]=='#');  mat w,ans; w[0][0]=cnt; w[0][1]=b; w[1][1]=c;  ans=Pow(w,k-1);  printf("%d\n",(ans[0][0]+P-ans[0][1])%P);  return 0;}
原创粉丝点击