题意
有 m m m 条竖线,每条线上有 n n n 个高度。从 ( 1 , 1 ) (1,1) (1,1) 出发,每次遇到横线时都选择经过它,并且不存在两条端点重合的横线,一条横线的两端点必须在同一高度,一条横线连接的需要是相邻的两条竖线。求从 ( 1 , 1 ) (1,1) (1,1) 到 ( h , k ) (h,k) (h,k) 的图的方案数。
思路
考虑 d p dp dp,我们可以用 d p i , j dp_{i,j} dpi,j 表示从 ( 1 , 1 ) (1,1) (1,1) 到 ( i , j ) (i,j) (i,j) 的方案数。
在此之前,我们需要先求一个东西,我们定义 f i , 0 f_{i,0} fi,0 为放到第 i i i 个位置不放边的方案数,定义 f i , 1 f_{i,1} fi,1 为放到第 i i i 个位置放边的方案数。不难想到:
f
i
,
0
←
f
i
−
1
,
0
+
f
i
−
1
,
1
f_{i,0} \gets f_{i-1,0}+f_{i-1,1}
fi,0←fi−1,0+fi−1,1
f
i
,
1
←
f
i
−
1
,
0
f_{i,1} \gets f_{i-1,0}
fi,1←fi−1,0
不难看出, ( i , j ) (i,j) (i,j) 可以由 ( i − 1 , j ) (i-1,j) (i−1,j), ( i − 1 , j − 1 ) (i-1,j-1) (i−1,j−1) 和 ( i − 1 , j + 1 ) (i-1,j+1) (i−1,j+1) 到达,即一个点上面三个点。
首先,假如是要直接由上面的点移下来,就需要要求上面那个点左边和右边都没有边,所以可以推出:
d p i , j ← d p i − 1 , j × f j − 1 , 0 × f m − j , 0 dp_{i,j} \gets dp_{i-1,j} \times f_{j-1,0} \times f_{m-j,0} dpi,j←dpi−1,j×fj−1,0×fm−j,0
接下来,如果是由左上的点推出,就需要要求上面那个点左边有边,而右边都没有边,所以可以推出:
d p i , j ← d p i − 1 , j − 1 × f j − 1 , 1 × f m − j , 0 dp_{i,j} \gets dp_{i-1,j-1} \times f_{j-1,1} \times f_{m-j,0} dpi,j←dpi−1,j−1×fj−1,1×fm−j,0
从右上的点推出的也同理。
d p i , j ← d p i − 1 , j + 1 × f j − 1 , 0 × f m − j , 1 dp_{i,j} \gets dp_{i-1,j+1} \times f_{j-1,0} \times f_{m-j,1} dpi,j←dpi−1,j+1×fj−1,0×fm−j,1
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1000000007;
int n,m,k;
int f[105][2],dp[105][105];
signed main(){
scanf("%lld%lld%lld",&n,&m,&k);
f[0][0]=1;
for(int i=1;i<=m;i++){
f[i][0]=(f[i-1][0]+f[i-1][1])%mod;
f[i][1]=f[i-1][0];
}
dp[0][1]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
dp[i][j]=(dp[i][j]+((dp[i-1][j]*((f[j-1][0]*f[m-j][0])%mod)%mod)%mod))%mod;
dp[i][j]=(dp[i][j]+((dp[i-1][j-1]*((f[j-1][1]*f[m-j][0])%mod)%mod)%mod))%mod;
dp[i][j]=(dp[i][j]+((dp[i-1][j+1]*((f[j-1][0]*f[m-j][1])%mod)%mod)%mod))%mod;
}
printf("%lld\n",dp[n][k]);
return 0;
}