题目大意:
题目链接:https://jzoj.net/senior/#main/show/5223
题目图片:
http://wx4.sinaimg.cn/mw690/0060lm7Tly1fy2w5kn4jbj30in0gk74z.jpg
给定一个
3
×
3
3\times3
3×3的网格图,一开始每个格子上都站着一个机器人。每一步机器人可以走到相邻格子或留在原地,同一个格子上可以有多个机器人。问走
n
n
n步后,有多少种走法,满足每个格子上都有机器人。答案对
1
0
9
+
7
10^9+7
109+7取模。
思路:
n
≤
1
0
18
n\leq 10^{18}
n≤1018告诉我们什么?
l
o
g
n
?
log\ n?
log n?显然不可做。
n
?
\sqrt{n}?
n?显然过不了。
3
×
3
3\times 3
3×3的矩阵?矩阵乘法!
设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示走
n
n
n步从格子
i
i
i到格子
j
j
j的方案数。那么很明显,中间矩阵
a
a
a就是相邻格子为
1
1
1,否则为
0
0
0。然后枚举每一个起始格子,跑一边矩阵乘法。就可以得到任意两点走
n
n
n步的方案数。
然后就
D
F
S
DFS
DFS每一个格子的机器人最终会走到哪一个格子。然后求
a
n
s
ans
ans即可。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int MOD=1000000007;
ll n,f[10][10],a[10][10],ans;
bool used[10];
const ll A[10][10]=
{
{0,0,0,0,0,0,0,0,0,0},
{0,1,1,0,1,0,0,0,0,0},
{0,1,1,1,0,1,0,0,0,0},
{0,0,1,1,0,0,1,0,0,0},
{0,1,0,0,1,1,0,1,0,0},
{0,0,1,0,1,1,1,0,1,0},
{0,0,0,1,0,1,1,0,0,1},
{0,0,0,0,1,0,0,1,1,0},
{0,0,0,0,0,1,0,1,1,1},
{0,0,0,0,0,0,1,0,1,1}
};
void mul(int x)
{
ll c[10];
memset(c,0,sizeof(c));
for (int i=1;i<=9;i++)
for (int j=1;j<=9;j++)
c[j]=(c[j]+(f[x][i]*a[i][j]))%MOD;
memcpy(f[x],c,sizeof(f[x]));
}
void mulself()
{
ll c[10][10];
memset(c,0,sizeof(c));
for (int i=1;i<=9;i++)
for (int j=1;j<=9;j++)
for (int k=1;k<=9;k++)
c[i][j]=(c[i][j]+a[i][k]*a[k][j])%MOD;
memcpy(a,c,sizeof(a));
}
void ksm(ll m,int x)
{
while (m)
{
if (m&1) mul(x);
mulself();
m>>=1;
}
}
void dfs(int x,ll s)
{
if (x>9)
{
ans=(ans+s)%MOD;
return;
}
for (int i=1;i<=9;i++)
if (!used[i])
{
used[i]=1;
dfs(x+1,s*f[x][i]%MOD);
used[i]=0;
}
}
int main()
{
cin>>n;
for (int i=1;i<=9;i++)
{
f[i][i]=1;
memcpy(a,A,sizeof(a));
ksm(n,i);
}
dfs(1,1);
cout<<ans;
return 0;
}

本文探讨了一个3x3网格上的机器人走法计数问题,通过矩阵乘法和深度优先搜索策略,实现了对大规模步数下机器人分布状态的有效计算。特别关注了在n≤10^18条件下的算法优化。
4010

被折叠的 条评论
为什么被折叠?



