2018.12.08【NOIP提高组】模拟B组 JZOJ 5223 B

版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/84894326

描述

给定一个 3 × 3 3\times 3 的网格图,一开始每个格子上都站着一个机器人。每一步机器人可以走到相邻格子或留在原地,同一个格子上可以有多个机器人。问走 n n 步后,有多少种走法,满足每个格子上都有机器人。答案对 1 0 9 + 7 10^9+7 取模。

数据范围:
n 1 0 18 n\leq 10^{18}


思路

f [ i ] [ j ] f[i][j] 表示从第 i i 格走到第 j j 格的方案数,得到方程

f [ i ] [ j ] = f [ i ] [ j ] + f [ i 1 ] [ j ] + f [ i ] [ j 1 ] + f [ i ] [ j + 1 ] + f [ i + 1 ] [ j ] f[i][j]=f[i][j]+f[i-1][j]+f[i][j-1]+f[i][j+1]+f[i+1][j]

然后我们矩阵乘法加速一下

最后全排列( d f s dfs )枚举一下机器人的最终落点,计算即可

时间复杂度: O ( 81 l o g n + 9 ! ) O(81logn+9!)

拓展

若数据扩大成 m × m m\times m 的矩阵,则还需要另一个 d p dp ,时间复杂度: O ( n 2 l o g n ) O(n^2logn)


代码

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define WYC 1000000007
using namespace std;
typedef long long LL;
LL n,s,f[9][9];
int b[10]={0,1,2,3,4,5,6,7,8,9};
struct node{LL a[9][9];}x,ans;
bool vis[9];
inline LL ksc(LL a,LL b)//快速乘
{
    a%=WYC;b%=WYC;
    long long c=(long double)a*b/WYC;
    long long ans=a*b-c*WYC;
    if(ans<0) ans+=WYC;
    else if(ans>=WYC) ans-=WYC;
    return ans;
}
inline node mul(node x,node y)//矩阵乘法
{
    node c;
    memset(&c,0,sizeof(c));
    for(register int k=0;k<9;k++)
     for(register int i=0;i<9;i++)
      for(register int j=0;j<9;j++)
    (c.a[i][j]+=ksc(x.a[i][k],y.a[k][j]))%=WYC;
    return c;
}
inline void ksm(LL y)//矩阵乘法+预处理
{
	memset(&ans,0,sizeof(ans));
	memset(&x,0,sizeof(x));
	for(register int i=0;i<9;i++) ans.a[i][i]=1;
	x.a[0][0]=x.a[0][1]=x.a[0][3]=1;
	x.a[1][0]=x.a[1][1]=x.a[1][2]=x.a[1][4]=1;
	x.a[2][1]=x.a[2][2]=x.a[2][5]=1;
	x.a[3][0]=x.a[3][3]=x.a[3][4]=x.a[3][6]=1;
	x.a[4][1]=x.a[4][3]=x.a[4][4]=x.a[4][5]=x.a[4][7]=1;
	x.a[5][2]=x.a[5][4]=x.a[5][8]=x.a[5][5]=1;
	x.a[6][3]=x.a[6][7]=x.a[6][6]=1;
	x.a[7][4]=x.a[7][6]=x.a[7][7]=x.a[7][8]=1;
	x.a[8][5]=x.a[8][7]=x.a[8][8]=1;
	for(;y;x=mul(x,x),y>>=1)if(y&1)ans=mul(ans,x);
	return;
}
inline char Getchar()
{
    static char buf[100000],*p1=buf+100000,*pend=buf+100000;
    if(p1==pend)
	{
        p1=buf; pend=buf+fread(buf,1,100000,stdin);
        if (pend==p1) return -1;
    }
    return *p1++;
}
inline long long read()
{
	char c;int d=1;long long f=0;
	while(c=Getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=Getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
inline void write(register long long x)
{
	if(x<0)write(45),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+48);
	return;
}
signed main()
{
	n=read();
	ksm(n);//矩阵乘法快速幂
	memcpy(f,ans.a,sizeof(ans.a));
	do
	{
		LL now=1;
		for(register int i=0;i<9;i++) (now*=f[i][b[i]])%=WYC;
		(s+=now)%=WYC;
	}while(next_permutation(b,b+9));//枚举全排列
	write(s);//输出
}
```

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/84894326