8数码问题的扩展,给定一个n*m的局面,问是否有解。局面按题目规则生成。
将此问题称作扩展8数码问题的话,通过观察基本操作可以发现,对于x,在只影响x右下角格子的前提下,我们一定可以移到指定的位置。这样我们可以依次将1,2,3,...等格子归位。只剩下右下角四个格子的顺序不定。严格的说,是(n,m-1)与(n-1,m)的格子不能确定是否恰好在其位置上。枚举最简单的2*2情况可以发现,将数字按照每行每列的顺序写成一个排列后,其逆序对为奇数的时候不可以归位,偶数的时候可以归位。这相当于,移到最后,如果右下角四个格子的逆序对数为偶数,整个问题有解,否则整个问题无解。
还可以发现,之前我们的任何操作都不会改变逆序对的个数,因为考虑:
1.空格的横向移动:排列不发生改变,逆序对奇偶性不改变;
2.空格的竖向移动:相当于做了(m-1)次交换,由于最后空格回到了右下角,即竖向交换的次数为偶数次,设为2K,则总体交换次数为2K*(m-1)次,也不改变逆序对的奇偶性。
故全图剩右下角四个格子没处理时,排列的逆序对奇偶性和原问题排列逆序对的奇偶性是一样的。可以推出,原问题逆序对奇偶性为偶数的时候,有解;反之无解。
在计算逆序对奇偶性的时候,对于每个放入的值,其后面比它小的数相当于留下的插空,这个在演算纸上模拟一下就可以发现,公式可以看代码。
#include <cstdio>
int T;
long long res,n,m,P;
int main()
{
scanf("%d",&T);
while (T--) {
res=0;
scanf("%I64d%I64d%I64d",&n,&m,&P);
n=n*m-1;
while (n>P) {
long long t=(n+P-1)/P;
res+=t*(t-1)*(P-1)/2LL;
n-=t;
}
puts(res%2?"NO":"YES");
}
return 0;
}