%%%
参考自:yts1999’s blog
题目链接 : Codie Bird
sol:
- 考虑朴素的 d p dp dp方程
d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + d p [ i − 1 ] [ j ] + d p [ i ] [ j + 1 ] dp[i][j] = dp[i-1][j-1]+dp[i-1][j]+dp[i][j+1] dp[i][j]=dp[i−1][j−1]+dp[i−1][j]+dp[i][j+1]
递推矩阵大概长这样。
T
=
[
1
1
0
0
0
0
…
0
0
1
1
1
0
0
0
…
0
0
0
1
1
1
0
0
…
0
0
…
…
…
…
…
…
…
…
…
0
0
0
0
0
0
…
1
1
]
T=\begin{bmatrix} 1 & 1 & 0 & 0 & 0 & 0 & \dots & 0 & 0 \\ 1 & 1 & 1 & 0 & 0 & 0 & \dots & 0 & 0 \\ 0 & 1 & 1 & 1 & 0 & 0 & \dots & 0 & 0 \\ \dots & \dots & \dots & \dots & \dots & \dots & \dots & \dots & \dots \\ 0 & 0 & 0 & 0 & 0 & 0 & \dots & 1 & 1\\ \end{bmatrix}
T=⎣⎢⎢⎢⎢⎡110…0111…0011…0001…0000…0000…0……………000…1000…1⎦⎥⎥⎥⎥⎤
有障碍的时候,将
[
1
,
a
]
[1,a]
[1,a]和
[
b
,
m
]
[b,m]
[b,m]列的矩阵元素全部置为0。将这个转移矩阵设为
S
S
S.
设
v
i
=
[
d
p
[
i
]
[
1
]
d
p
[
i
]
[
2
]
⋯
d
p
[
i
]
[
k
]
]
v_i=\begin{bmatrix} dp[i][1] & dp[i][2] & \cdots & dp[i][k]\end{bmatrix}
vi=[dp[i][1]dp[i][2]⋯dp[i][k]],则
v
n
=
v
1
(
∑
i
=
1
n
−
2
T
i
−
1
S
T
n
−
2
−
i
)
T
v_n=v_1(\sum\limits_{i=1}^{n-2}T^{i-1}ST^{n-2-i})T
vn=v1(i=1∑n−2Ti−1STn−2−i)T。
设
P
n
=
∑
i
=
1
n
T
i
−
1
S
T
n
−
i
P_n = \sum\limits_{i=1}^{n} T^{i-1}ST^{n-i}
Pn=i=1∑nTi−1STn−i,则
v
n
=
v
1
P
n
−
2
T
v_n = v_1P_{n-2}T
vn=v1Pn−2T。
实现上可以用单位矩阵代替
v
1
v_1
v1,
v
n
v_n
vn就是最终矩阵的第
k
2
\frac{k}{2}
2k行。
- 求 P n P_n Pn可以用类似倍增的做法。
P
1
=
S
P_1 = S
P1=S
若n为偶数,
P
n
=
P
n
2
⋅
T
n
2
+
T
n
2
⋅
P
n
2
P_n = P_\frac{n}{2} \cdot T^\frac{n}{2} + T^\frac{n}{2} \cdot P_\frac{n}{2}
Pn=P2n⋅T2n+T2n⋅P2n
若n为奇数,
P
n
=
P
n
−
1
⋅
T
+
T
n
−
1
⋅
S
P_n = P_{n-1} \cdot T + T^{n-1} \cdot S
Pn=Pn−1⋅T+Tn−1⋅S
实现上可以考虑 101 0 ( 2 ) = 1 0 ( 10 ) 1010_{(2)} = 10_{(10)} 1010(2)=10(10)这样的求解过程。
code:
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 52;
const int mod = 1e9+7;
int n,m;
struct Mat{
ll a[maxn][maxn];
void init(int k){
memset(a,0,sizeof(a));
for(int i = 1;i<=k;i++) a[i][i] = 1;
}
void reset(){
memset(a,0,sizeof(a));
}
Mat operator + (Mat b){
Mat c;
c.reset();
for(int i = 1;i<=m;i++)
for(int j = 1;j<=m;j++)
c.a[i][j] = (a[i][j] + b.a[i][j]) % mod;
return c;
}
Mat operator * (Mat b){
Mat c;
for(int i = 1;i<=m;i++)
for(int j = 1;j<=m;j++){
c.a[i][j] = 0;
for(int k = 1;k<=m;k++){
c.a[i][j] += a[i][k] * b.a[k][j] % mod;
}
c.a[i][j] %= mod;
}
return c;
}
Mat pow(int b){
Mat ret; ret.init(m);
Mat a = (*this);
while(b){
if(b&1) ret = ret * a;
a = a * a;
b>>=1;
}
return ret;
}
};
ll qpow(ll a,int b){
ll ret = 1;
while(b){
if(b&1) ret = ret * a % mod;
a = a*a % mod;
b>>=1;
}
return ret;
}
int main(){
int a,b;
scanf("%d%d%d%d",&n,&m,&a,&b);
n -= 2;
Mat T,S;
T.reset(); S.reset();
for(int i = 1;i<=m;i++)
T.a[i][i] = T.a[i][i-1] = T.a[i][i+1] = 1;
S = T;
for(int i = 1;i<=m;i++){
if(i<=a || i>=b){
for(int j = 1;j<=m;j++){
S.a[j][i] = 0;
}
}
}
int bit = 0;
for(int i = n;i>0;i>>=1) bit++;
Mat P = S; Mat Ts = T;
for(int i = bit - 2;i>=0;i--){
P = P * Ts + Ts * P;
Ts = Ts * Ts;
if((n>>i)&1){
P = P * T + Ts * S;
Ts = Ts * T;
}
}
P = P * T;
ll ans = P.a[m/2][m/2];
ans = ans * qpow(n,mod-2) % mod;
printf("%lld\n",ans);
return 0;
}