其中前两种可以直接按题意从
x
x
x转移到
x
−
1
,
x
,
x
+
1
x-1,x,x+1
x−1,x,x+1,而第三种要从障碍左边那列转移到障碍右边,枚举左边
x
−
1
,
x
,
x
+
1
x-1,x,x+1
x−1,x,x+1,右边
x
−
1
,
x
,
x
+
1
x-1,x,x+1
x−1,x,x+1,
3
∗
3
=
9
3*3=9
3∗3=9种转移,而障碍那列直接跳过,
于是这样最后矩乘做
n
−
2
n-2
n−2次。
但常数比较大,可能需要优化,矩乘中省去一些没有用的转移即可。
代码
#include<cstdio>#include<cstring>#include<algorithm>usingnamespace std;#define N 265#define ll unsigned long long#define md 1000000007int n, m, A, B;
ll c[N][N], f[N][N], g[N][N];
ll qpw(ll x, ll y){if(!y)return1;
ll l =qpw(x, y /2);if(y %2)return l * l % md * x % md;return l * l % md;}voidksm(int n){if(n ==0){for(int i =1; i <= m *2; i++) f[i][i]=1;}else{ksm(n /2);memset(g,0,sizeof(g));for(int i =1; i <= m *2; i++)for(int j =(i > m)?(m +1):1; j <= m *2; j++)for(int k =(i > m)?(m +1):1; k <=((j > m)? m *2: m); k++){if(k %18==0) g[i][j]%= md;
g[i][j]+= f[i][k]* f[k][j];}for(int i =1; i <= m *2; i++)for(int j =1; j <= m *2; j++) f[i][j]= g[i][j]% md;if(n %2){memset(g,0,sizeof(g));for(int i =1; i <= m *2; i++)for(int j =(i > m)?(m +1):1; j <= m *2; j++){int x = j;if(x > m) x -= m;for(int k =max(x -2,0); k <=min(x +2, m *2); k++) g[i][j]+= f[i][k]* c[k][j];
x += m;for(int k =max(x -2,0); k <=min(x +2, m *2); k++) g[i][j]+= f[i][k]* c[k][j];}for(int i =1; i <= m *2; i++)for(int j =1; j <= m *2; j++) f[i][j]= g[i][j]% md;}}}intmain(){int i, j, k;scanf("%d%d%d%d",&n,&m,&A,&B);for(i =1; i <= m + m; i++){if(i == m) c[i][i]= c[i][i -1]=1;elseif(i == m +1) c[i][i]= c[i][i +1]=1;else c[i][i]= c[i][i +1]= c[i][i -1]=1;}for(i = A +1; i < B; i++)for(j =-1; j <2; j++)if(i + j <= m)for(k =-1; k <2; k++)if(i + k) c[i + j][i + m + k]++;ksm(n -2);printf("%lld
", f[m /2][m /2*3]*qpw(n -2, md -2)% md);return0;}