题意:
就是通过移动空格(用0代替)使得原来状态变成有序的1234......0
分析:
以数组为一维的举例子.
将八数码的一个结点表示成一个数组a[9],空格用0表示,设临时函数p(x)定义为:x数所在位置前面的数比x小的数的个数,
其中0空格不算在之内,那设目标状态为b[9],那r=sigma(p(x)) sigma()表示取所有的x:1-8并求和,
那对于初始状态a[9],t=sigma(p(x)),如果r和t同为奇数或者同为偶数,那么该状态有解,否则无解。
考虑到四种移动方法对sigma(p(x))的影响,左移和右移是不会影响它的值的,
更不会影响奇偶性,如果是上移或者下移就会影响:
上移:一次上移会使一个元素向前跳两个数字的位置,设这两个数字为a1,a2,
不妨设a1<a2,移的这个数字设为a0,那无非只有以下三次情况:
1,a0<a1<a2,考虑它们三者的p(x)值,p(a0)不变,p(a1)++,p(a2)++,总体增加了2
2,a1<a0<a2,p(a0)--,p(a1)不变,p(a2)++,总体不变
3,a1<a2<a0,p(a0)-=2,p(a1),p(a2)不变,总体减小了2
综合起来的结论就是不会影响sigma(p(x))的奇偶性。
接着考虑列数的奇偶。
-------------0***********
***********x-------------
x是任意数,现在要把x移上去,那么***********中,假设有a个大于x,b个小于x,那么移动之后逆序数就会加上一个b-a,x所能影响的也就是这些罢了,除此之外,其他都不变。
那么******的个数就是奇数,b,a奇偶性互异,b-a为奇数,所以移动一次后,原序列的逆序数的奇偶性变了。
考虑到最后0会移动到最后一行,所以奇偶性会改变n-i次(i为0的行数),只需判断最后是否是偶数即可。
反之,如果列数为奇数,那么******的个数就是偶数,b,a奇偶性相同,b-a为偶数,所以移动一次后,原序列的逆序数的奇偶性没变。
因为无论怎么移,奇偶性都不变,所以说一开始初态的奇偶性就必须与末态一致。
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e6+10;
int a[maxn],c[maxn];
int lowbit(int i){
return i&(-i);
}
void insert(int i,int x){
for(;i<maxn;i+=lowbit(i)){
c[i]+=x;
}
}
int getsum(int i){
int sum=0;
for(;i;i-=lowbit(i)){
sum+=c[i];
}
return sum;
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)&&(n||m)){
int x,sum=0,num=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int b;
scanf("%d",&b);
if(b){
a[num++]=b;
}else x=n-i;
}
}
memset(c,0,sizeof c);
for(int i=num-1;i>=0;i--){
sum+=getsum(a[i]-1);
insert(a[i],1);
}
if(m&1){
if(sum&1) printf("NO\n");
else printf("YES\n");
}else {
if((x^sum)&1) printf("NO\n");
else printf("YES\n");
}
}
return 0;
}