[ARC171E] Rookhopper's Tour 题解
首先把 \(m=2\) 和 \(m\) 为奇数的情况判掉,由于我们要对合法的摆放方案计数,而一个摆放方案要判断合法性就必须通过一组合法的移动过程,对移动的状态进行记录以此转移和优化显然没啥前途,因此我们考虑摆放方案和移动过程之间的联系。
一个比较显然的观察是摆放方案和移动过程是一组双射,移动显然能还原唯一一组摆放,那反过来呢?我们只要考虑移动过程形成的环能不能逆着走就行,你尝试构造会发现这个摆放方案其实比较唯一而且不合法。
那接下来我们就开始对移动过程计数,同样此时也出现了一个问题:什么样的移动方案是合法的?
对白色石头的限制是任意两个白色石头都不能出现在同一行或者同一列,如果你有尝试画出路线就会发现这引出了一条对于路线的限制:跳过一个白色石头之后必然要拐弯,原因显然,也就是说我们其实是在交错横向纵向移动,这其实启发我们把两个维度拆开考虑。
而两个白色石头能出现在同一行或者同一列,我们会想去思考:那移动过程中的两个黑色石头能不能出现在同一行或者同一列?
为了引出这个这个条件,我们尝试把黑色和白色石头捆绑考虑,和一个黑色石头捆绑的那个白色石头的位置取决于黑色石头移动过来的方向,再画画图,会发现这个黑色石头再纵向移动的时候其实还带来了一个在这一列的白色石头,如果我们只看行这一位其实这个横向移动带来了在这个方向上的两个障碍,读者可以画画图自己感受一下。
也就是说,我们每次横向移动的黑色石头不能与前面的黑色石头重合,也不能和前面那个跳过的白色石头重合,但前面这个白色石头的相对位置是不确定的,这为我们计数带来了一些困难。
先整理一下情况,现有的条件要求我们对一个大概是选出若干个横坐标表示每次移动到这个坐标,然后这些坐标及其带来的附加东西不能重合,这个附加东西和坐标组成一个大小为 2 的块,然后我们要对这个东西组成的序列计数。
整理完之后就会发现其实我们只要把那一堆看做一个大小为 2 的块然后求在序列里面放这个东西不能重叠的方案数就好了,因为序列是有遍历顺序的,一个顺序就唯一确定了黑色和白色石头的相对位置,跟原本的移动路径就是双射。
最后还有一点小问题,就是我们回到最开始的那个黑色块所带来的白色块的位置是不确定的,我们枚举它,然后就要求在一行里面放下若干个长度为 2 的块,不能重叠,块有标号且最大标号的块一定在我们枚举的那个方向,组合数随便算算就行,记得最后答案乘二,因为我们不知道是先走横的还是先走竖的。
ll solve(ll n,ll m,ll x){
ll ans=0;
for(ll i=0;i<m;i++){
ans=(ans+(i*fac[m-2]%mod)*(C(x-2-i,i)*C(n-x-(m-i-1),m-i-1)%mod))%mod;
ans=(ans+((m-i-1)*fac[m-2]%mod)*(C(x-1-i,i)*C(n-x-1-(m-i-1),m-i-1)%mod))%mod;
}
return ans;
}
int main(){
ll n=read(),m=read(),a=read(),b=read();prework();
if(m&1 || m==2){cout<<0;return 0;}
cout<<(solve(n,m/2,a)*solve(n,m/2,b)*2)%mod;
return 0;
}