题目
有一个H*M的棋盘,起初小车在x1 , y1 ,小车要到达x2 , y2 。
小车每次操作只能到达棋盘中同行或者同列的某个位置。
要求计算小车从起点到达终点,并且恰好使用K次操作的方法数。
答案对998244353取余。
题解思路
这种问题可以先想想将行列分开考虑。
我们可以根据最后一个不同点来划分,即小车到没到达目标的行或列。
以横坐标为例
即
dp[ i ] [ 0 ] 表示小车走了 i 步 走完后不在 目标的列 ,1 表示在目标的列 的所有合法方案 。
根据这个条件 , 很容易得出转移方程。
dx[i][1] = dx[i-1][0]%mod ;
dx[i][0] = dx[i-1][1]*(h-1)%mod + dx[i-1][0]*(h-2)%mod ;
最后能到达终点的必然是 x y 都到达了终点 , 即他们的状态都是 1 ,
我们进行组合即可。
现在走了dx[ i ][ 1 ] * dy[ k - i ][ 1 ] 。
现在知道要走分别要几步的方案了。
但是对x y 步数的顺序 还得进行组合。
即从k步中选择i步来走x。
这里就用到了组合数。
这样就得用到逆元了。
AC代码
#include <bits/stdc++.h>
//#include <unordered_map>
//priority_queue
#define PII pair<int,int>
#define ll long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 1000100;
const int mod = 998244353 ;
long long dx[N][3] ;
long long dy[N][3] ;
long long jc[N] ;
long long ksm(long long di , long long mi )
{
long long res = 1 ;
while ( mi )
{
if ( mi & 1 )
res = res*di %mod ;
di = di*di%mod ;
mi >>= 1 ;
}
return res ;
}
long long zuhe(int n , int m )
{
return jc[n]*ksm(jc[n-m],mod-2)%mod*ksm(jc[m],mod-2)%mod ;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int h , w , k ;
cin >> h >> w >> k ;
int x1 , x2 , y1 , y2 ;
cin >> x1 >> y1 >> x2 >> y2 ;
jc[0] = 1 ;
for (int i = 1 ; i <= k ; i++ )
jc[i] = jc[i-1]*i%mod ;
if ( x1 != x2 )
dx[0][0] = 1 ;
else
dx[0][1] = 1 ;
if ( y1 != y2 )
dy[0][0] = 1 ;
else
dy[0][1] = 1 ;
for (int i = 1 ; i <= k ; i++ )
{
dx[i][1] = dx[i-1][0]%mod ;
dx[i][0] = dx[i-1][1]*(h-1)%mod + dx[i-1][0]*(h-2)%mod ;
dy[i][1] = dy[i-1][0]%mod ;
dy[i][0] = dy[i-1][1]*(w-1)%mod + dy[i-1][0]*(w-2)%mod ;
}
long long ans = 0 ;
for (int i = 0 ; i <= k ; i++ )
{
long long sk = dx[i][1]*dy[k-i][1]%mod ;
sk = sk*zuhe(k,i)%mod ;
ans = (ans + sk)%mod ;
}
cout << ans << "\n" ;
return 0 ;
}