1. 程式人生 > >2018.12.08【NOIP提高組】模擬B組 JZOJ 5223 B

2018.12.08【NOIP提高組】模擬B組 JZOJ 5223 B

描述

給定一個 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);//輸出
}
```