BZOJ2973 : 石頭遊戲

Claris發表於2015-08-14

考慮到$lcm(1,2,3,4,5,6)=60$,所以操作序列每60秒一個迴圈。

將操作表示成轉移矩陣的形式,預處理出前60秒的轉移矩陣以及它們的乘積$B$。

那麼t秒的轉移矩陣為前$t\bmod 60$個轉移矩陣的乘積乘以$B^{\lfloor\frac{t}{60}\rfloor}$。

用矩陣快速冪加速計算即可。

 

#include<cstdio>
#include<cstring>
#define rep(i,n) for(int i=0;i<n;i++)
#define P 65
typedef long long ll;
int n,m,t,q,i,j,k,x,y,N,id[P][P],a[P][P],l[P];char s[P],b[P][P],c;ll ans;
struct mat{
  ll a[P][P];
  mat(){rep(i,P)rep(j,P)a[i][j]=0;}
  inline mat operator*(mat b){
    mat c;
    rep(i,N)rep(j,N)rep(k,N)c.a[i][j]+=a[i][k]*b.a[k][j];
    return c;
  }
}one,A[P],pre[P],B,C,D;
int main(){
  scanf("%d%d%d%d",&n,&m,&t,&q);
  for(i=1;i<=n;i++)for(scanf("%s",s+1),j=1;j<=m;j++)id[i][j]=++N,a[i][j]=s[j]-'0';N++;
  for(i=0;i<q;i++)scanf("%s",b[i]+1),l[i]=std::strlen(b[i]+1),b[i][0]=b[i][l[i]];
  rep(i,N)one.a[i][i]=1;
  for(pre[0]=one,i=1;i<=60;i++){
    A[i].a[0][0]=1;
    for(j=1;j<=n;j++)for(k=1;k<=m;k++){
      c=b[a[j][k]][i%l[a[j][k]]];
      if(c>='0'&&c<='9')A[i].a[id[j][k]][0]=c-'0',A[i].a[id[j][k]][id[j][k]]++;
      if(c=='N'){
        x=j-1,y=k;
        if(x>=1)A[i].a[id[x][y]][id[j][k]]++;
      }
      if(c=='S'){
        x=j+1,y=k;
        if(x<=n)A[i].a[id[x][y]][id[j][k]]++;
      }
      if(c=='W'){
        x=j,y=k-1;
        if(y>=1)A[i].a[id[x][y]][id[j][k]]++;
      }
      if(c=='E'){
        x=j,y=k+1;
        if(y<=m)A[i].a[id[x][y]][id[j][k]]++;
      }
    }
    pre[i]=A[i]*pre[i-1];
  }
  for(B=pre[60],C=one,k=t/60;k;k>>=1,B=B*B)if(k&1)C=C*B;
  for(D.a[0][0]=1,D=pre[t%60]*C*D,i=1;i<N;i++)if(ans<D.a[i][0])ans=D.a[i][0];
  return printf("%lld",ans),0;
}

  

相關文章