给出一个 n ⋅ m n \cdot m n⋅m的字符矩阵,将此矩阵无限延长,现在选一个起点和一个方向(8个方向)走 K K K步得到的字符串,求走两次得到的两个字符串相同的概率。
n , m ≤ 200 , K ≤ 1 0 9 n,m\le 200,K\le 10^9 n,m≤200,K≤109
#include
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i=i##_end_;--i)
#define ll long long
#define ull unsigned long long
#define fi first
#define se second
const int N=202,M=21;
const int d[]={0,-1,1};
ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}
int n,m,K;
char s[N][N];
typedef pairpii;
struct node{
int x,y;
pii v;
}dp[M][N][N];
/*
dp[k][i][j] 表示 (i,j) 走 2^k-1步的情况
*/
int bit[M],num;
int tot;
pii A[N*N*8];
pii Step[M],Base[M];
ll base1=133,base2=137;
/*
这里Hash还是建议双Hash,懒一点可以用unsigned long long,一般卡不掉...
强烈建议多Hash时将Hash包个struct,再写一个重载符,个人觉得比函数较方便
*/
pii operator*(pii a,pii b){
pii c;
c.fi=a.fi*b.fi;
c.se=a.se*b.se;
return c;
}
pii operator+(pii a,pii b){
pii c;
c.fi=a.fi+b.fi;
c.se=a.se+b.se;
return c;
}
node DP(node a,pii BASE,int nxt){
node b=dp[nxt][a.x][a.y];
return (node){b.x,b.y,b.v*BASE+a.v};
// 下个点 //路径Hash
}
void solve(int Dx,int Dy){
SREP(x,0,n) SREP(y,0,m){
int nx=(x+Dx+n)%n;
int ny=(y+Dy+m)%m;
dp[0][x][y]=(node){nx,ny,make_pair(s[x][y],s[x][y])};//初始
}
REP(i,1,bit[num-1]) SREP(x,0,n) SREP(y,0,m) dp[i][x][y]=DP(dp[i-1][x][y],Base[i-1],i-1);
SREP(x,0,n) SREP(y,0,m) {
node res=(node){x,y,(pii){0,0}};
SREP(i,0,num) res=DP(res,Step[i],bit[i]);
A[++tot]=res.v;// 记录该方向上(x,y)的终态
}
}
int main(){
// freopen("genius.in","r",stdin);
// freopen("genius.out","w",stdout);
scanf("%d%d%d",&n,&m,&K);
SREP(i,0,n) scanf("%s",s[i]);
Base[0]=(pii){(ull)base1,(ull)base2};
SREP(i,1,M) Base[i]=Base[i-1]*Base[i-1];
SREP(i,0,M) if(K&(1<