题目翻译

有一个 $H\times W$ 的国际象棋棋盘,求一个从 $(x_1,y_1)$ 走到 $(x_2,y_2)$ 正好用 $K$ 步的方案数。

题目思路

首先看到题,很显然是动态规划。$f_{k,i,j}$ 表示走到 $(i,j)$ 正好 $k$ 步的方案。但时间复杂度过高,考虑进行优化。

我们可以不记录具体走到哪个点位,我们只需知道当前在不在起点即可。于是就有 $f_{k,0/1/2/3}$ 表示第 $k$ 步时,当前位置为 $(x_1,y_1),(x_1,非y_1),(非x_1,y_1),(非x_1,非y_1)$。

我们在运用一些排列组合的基本知识,便能得到以下转移方程:

$$
f_{k,0} = f_{k-1,1} \times (W-1) + f_{k,2} \times (H-1)
$$

$$
f_{k,1} = f_{k-1,1} \times (W-2) + f_{k,0} + f_{k,3} \times (H-1)
$$

$$
f_{k,2} = f_{k-1,2} \times (H-2) + f_{k,0} + f_{k,3} \times (W-1)
$$

$$
f_{k,3} = f_{k-1,3} \times (H+W-4) + f_{k,2} + f_{k,1}
$$

接着,我们再循环过程中是可以压掉第一维 $k$ 的,那么我们只需记录 $4$ 个变量即可。

完整代码

远古时期代码,码风有点不好请见谅。

#include<bits/stdc++.h>
#define ll long long
#define p 998244353
using namespace std;
long long a,b,c,d;
int main()
{
    ll h,w,k,xx1,xx2,yy1,yy2;
    cin>>h>>w>>k>>xx1>>yy1>>xx2>>yy2;
    a=1;
    for(int i=0;i<k;i++)
    {
        ll a1,b1,c1,d1;
        a1=b*(w-1)+c*(h-1);
        b1=b*(w-2)+a+d*(h-1);
        c1=c*(h-2)+a+d*(w-1);
        d1=d*(h+w-4)+b+c;
        a1%=p;
        b1%=p;
        c1%=p;
        d1%=p;
        a=a1;
        b=b1;
        c=c1;
        d=d1;
    }
    if(xx2==xx1&&yy2==yy1)cout<<a%p;
    else if(xx2==xx1)cout<<b%p;
    else if(yy2==yy1)cout<<c%p;
    else cout<<d%p;
    return 0;
}
最后修改:2023 年 04 月 22 日
v我50吃疯狂星期四