题目大意
给定一个3*3的网格图,一开始每个格子上都站着一个机器人。每一步机器人可以走到相邻格子或留在原地,同一个格子上可以有多个机器人。问走n步后,有多少种走法,满足每个格子上都有机器人。答案对10^9+7取模。
解题思路
考虑到点数较小,暴力枚举每个点最后到哪里,用矩阵乘法算出从一个点到能一个点的方案数,乘起来即可。
code
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LF double
#define LL long long
#define ULL unsigned int
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define fr(i,j) for(int i=begin[j];i;i=next[i])
using namespace std;
int max(int x,int y){return (x>y)?x:y;}
int min(int x,int y){return (x<y)?x:y;}
int const mn=1e6+9,mo=1e9+7;
int a[20],vis[20];
LL n,anss,ans[20][20],mat[20][20],tmp[20][20];
void multansmat(){
fo(i,1,9)fo(j,1,9)tmp[i][j]=0;
fo(i,1,9)fo(j,1,9)fo(k,1,9)tmp[i][k]=(tmp[i][k]+ans[i][j]*mat[j][k])%mo;
fo(i,1,9)fo(j,1,9)ans[i][j]=tmp[i][j];
}
void multmatmat(){
fo(i,1,9)fo(j,1,9)tmp[i][j]=0;
fo(i,1,9)fo(j,1,9)fo(k,1,9)tmp[i][k]=(tmp[i][k]+mat[i][j]*mat[j][k])%mo;
fo(i,1,9)fo(j,1,9)mat[i][j]=tmp[i][j];
}
void dfs(int now){
if(now>9){
LL tmp=1;
fo(i,1,9)tmp=tmp*ans[i][a[i]]%mo;
anss=(anss+tmp)%mo;
return;
}
fo(i,1,9)if(!vis[i]){
a[now]=i;
vis[i]=1;
dfs(now+1);
vis[i]=0;
}
}
int main(){
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%lld",&n);
fo(i,1,9)ans[i][i]=1;
mat[1][1]=mat[1][2]=mat[1][4]=1;
mat[2][1]=mat[2][2]=mat[2][3]=mat[2][5]=1;
mat[3][2]=mat[3][3]=mat[3][6]=1;
mat[4][1]=mat[4][4]=mat[4][5]=mat[4][7]=1;
mat[5][2]=mat[5][4]=mat[5][5]=mat[5][6]=mat[5][8]=1;
mat[6][3]=mat[6][5]=mat[6][6]=mat[6][9]=1;
mat[7][4]=mat[7][7]=mat[7][8]=1;
mat[8][5]=mat[8][7]=mat[8][8]=mat[8][9]=1;
mat[9][6]=mat[9][8]=mat[9][9]=1;
while(n){
if(n&1)multansmat();
multmatmat();
n>>=1;
}
dfs(1);
printf("%lld",anss);
return 0;
}