poj2893 M×N puzzle
x数码难题有解性判定:
只有必要性证明,没有充分性......
还记得那个naive至极的八数码难题吗?
它回来了!
主要是借助逆序对这一神奇的手段:
考虑把x数码写成一排时的逆序对的奇偶性:
当你左右挪时显然没有影响。
当你上下挪时:列数为奇数则对逆序对奇偶性无影响,为偶数则变动。
然后我们就按照这个莫名其妙的法则A题......666
(注意:此法则不能容许有相同数字。否则奇偶性随机变化,无从下手)
1 // poj 2893 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int N = 1001; 6 const int N2 = N * N; 7 int g[N][N]; 8 typedef long long LL; 9 struct TreeArray { 10 int a[N2]; 11 void clear() { 12 memset(a, 0, sizeof(a)); 13 return; 14 } 15 int lowbit(int x) { 16 return x & (-x); 17 } 18 void add(int x, int y) { 19 if(x == 0) { 20 return; 21 } 22 for(int i = x; i < N2; i += lowbit(i)) { 23 a[i] += y; 24 } 25 return; 26 } 27 int getsum(int x) { 28 if(x == 0) { 29 return 0; 30 } 31 int ans = 0; 32 for(int i = x; i > 0; i -= lowbit(i)) { 33 ans += a[i]; 34 } 35 return ans; 36 } 37 int ask(int l, int r) { 38 return getsum(r) - getsum(l - 1); 39 } 40 }ta; 41 42 int main() { 43 int a, b, xx, yy; 44 scanf("%d%d", &a, &b); 45 while(a || b) { 46 ta.clear(); 47 for(int i = 1; i <= a; i++) { 48 for(int j = 1; j <= b; j++) { 49 scanf("%d", &g[i][j]); 50 if(!g[i][j]) { 51 xx = i; 52 yy = j; 53 } 54 } 55 } 56 // 本题不用离散化 57 LL ans = 0; 58 for(int i = a; i >= 1; i--) { 59 for(int j = b; j >= 1; j--) { 60 if(g[i][j]) { 61 ans += ta.getsum(g[i][j] - 1); 62 ta.add(g[i][j], 1); 63 } 64 } 65 } 66 if(!(b & 1)) { 67 ans += (a - xx); 68 } 69 if(ans & 1) { 70 printf("NO\n"); 71 } 72 else printf("YES\n"); 73 scanf("%d%d", &a, &b); 74 } 75 return 0; 76 }