【JZOJ5223】B【矩阵乘法】【DFS】

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

题目大意:

题目链接: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} n1018告诉我们什么?
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;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值