【练习——逆序对】N*M Puzzle / Simple Puzzle

HDU P3600 Simple Puzzle

POJ P2893 N*M Puzzle

(咕在前面, 这是两道基本一样的题, 我都没有A掉, 但我觉得我写的十分正确!!!不想改了先放上来orz

思路:这个题真是妙啊qwq我特意新建了一个“妙啊”分类给它qwq(然而A不掉

  • 将二维转化为一维, 从左往右从上至下, 遇到0(空格)跳之~
  • 可知空格左右移动对一维序列无影响, 上下移动会向前或向后移动, 跳过(m-1)个格子//这里n行m列
  • 如果列数为奇数, (m-1)为偶数, 则无论移动的数与跳过的数的大小关系如何, 逆序对数奇偶性不变;
  • 也就是说具有同奇偶性的逆序对数的数列是可以互相转化的, 初始数列逆序对数为0, 只要逆序对数为偶数, 即可输出“YES”
  • 如果列数为偶数, (m-1)为奇数, 则无论移动的数与跳过的数的大小关系如何, 逆序对数奇偶性一定改变;
  • 同理, 空格移动行数若为奇数, 逆序对数奇偶性发生改变
  • (太乱了!!!!贴个讲的清楚地QAQ

贴上我可怜的无助的至今在两大oj还是wa的代码!(输入格式附和POJ

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 using namespace std;
 5 const int sz = 1000;
 6 int n, m, flag, num = 0, cnt = 0, x, a[sz*sz], b[sz*sz];
 7 void merge_sort(int l, int r) {
 8     if(r - l > 0) {
 9         int mid = (l + r) >> 1;
10         int i = l, p = l, q = mid + 1;
11         merge_sort(l, mid);
12         merge_sort(mid+1, r);
13         while(q <= r|| p <= mid) {
14             if(q > r || (p <= mid && a[p] <= a[q]))
15                 b[i++] = a[p++];
16             else b[i++] = a[q++], cnt = cnt + mid - p + 1;
17         }
18         for(int i = l; i <= r; i++)
19             a[i] = b[i];
20     }
21 }
22 int main() {
23     while(1) {
24         scanf("%d%d", &n, &m);
25         if(n==0&&m==0) break;
26         num = 0;
27         memset(a, 0, sizeof(a));
28         memset(b, 0, sizeof(b));
29         for(int i = 1; i <= n; i++) {
30             for(int j = 1; j <= m; j++) {
31                 scanf("%d", &x);
32                 if(x==0) {
33                     flag = i;
34                     continue;
35                 }
36                 a[++num] = x;
37             }
38         }
39         cnt = 0;
40         merge_sort(1, num);
41         if(m%2==1) {
42             if(cnt%2==1) {
43                 if((n-flag)%2==1) printf("YES\n");
44                 else printf("NO\n");
45             }
46             else {
47                 if((n-flag)%2==1) printf("NO\n");
48                 else printf("YES\n");
49             }
50         }
51         else {
52             if(cnt%2 == 0) printf("YES\n");
53             else printf("No\n");
54         }
55     }
56     return 0;
57 }

 

原文地址:https://www.cnblogs.com/Hwjia/p/9813319.html

时间: 2024-10-30 14:53:39

【练习——逆序对】N*M Puzzle / Simple Puzzle的相关文章

M &#215; N Puzzle - 逆序对【N*M数码问题局面之间可达性判定】

M × N Puzzle Sol: \(N*M\)数码某局面到达另一局面的可行性判定 可以通过逆序对个数的奇偶性是否相同来判定. 我们将这\(N*M-1\)个数写成一列来看. 考虑行为奇数,列为奇数的情况->逆序对个数奇偶性相同时可达 空格左右移动不会改变逆序对的个数,而上下移动相当于改变了该列前后共\(M-1\)个数的逆序对个数,由于\(M-1\)是偶数,所以移动前后逆序对个数奇偶性不变. 考虑行为奇数,列为偶数的情况->(逆序对个数+前后状态空格行数之差)奇偶性相同时可达 上下移动会改变共

hdu多校第四场 1007 (hdu6620) Just an Old Puzzle 逆序对

题意: 给你一个数字拼图,问你数字拼图能否能复原成原来的样子. 题解: 数字拼图的性质是,逆序数奇偶相同时,可以互相转化,逆序数奇偶不同,不能互相转化. 因此统计逆序对即可. #include<iostream> using namespace std; int main(){ int t; scanf("%d",&t); while(t--){ int a[20]; int kg; for(int i=1;i<=16;i++){ scanf("%d

codeforces 414C C. Mashmokh and Reverse Operation(归并排序求逆序对)

题目链接: C. Mashmokh and Reverse Operation time limit per test 4 seconds memory limit per test 512 megabytes input standard input output standard output Mashmokh's boss, Bimokh, didn't like Mashmokh. So he fired him. Mashmokh decided to go to university

求逆序对(线段树版)

一个序列a1,a2,a3...aN,求出满足:ai > aj 且 i < j 的个数. 一个最容易想到的方法就是枚举所有的i,j看看是否满足,显然是O(n^2)的复杂度.不够好. 可以这样考虑,开一个数组保存这n个数出现的位置和对应的次数,这个数组要开到a数组里最大的那个数MAX,也就是hash,初始状态数组里没有元素,每个数对应的个数都是0. 如果考虑第i个数,找到比它大的所有的数 的个数,查找的范围即 ai+1~MAX,这就是到i这个位置的逆序对的总和,接着把a[i]这个数添加到数组里,也

剑指offer: 数组中的逆序对

1. 最简单的思路,对每个值,遍历与其逆序的数组对:但时间复杂度太高: 2. 归并排序的思路: 先将数组分隔成子数组,先统计出子数组内的逆序对的数目,然后统计两个相邻子数组之间的逆序对的数目: int InversePairsCore(int *data, int * copy, int start, int end) { //递归介绍条件,只剩一个元素 if(start==end) { copy[start]=data[start]; return 0; } int length=(end-s

[HAOI2009]逆序对数列

题目描述 对于一个数列{ai},如果有i<j且ai>aj,那么我们称ai与aj为一对逆序对数.若对于任意一个由1~n自然数组成的数列,可以很容易求出有多少个逆序对数.那么逆序对数为k的这样自然数数列到底有多少个? 输入输出格式 输入格式: 第一行为两个整数n,k. 输出格式: 写入一个整数,表示符合条件的数列个数,由于这个数可能很大,你只需输出该数对10000求余数后的结果. 输入输出样例 输入样例#1: 4 1 输出样例#1: 3 说明 样例说明: 下列3个数列逆序对数都为1:分别是1 2

bzoj3295动态逆序对

Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 5362  Solved: 1814[Submit][Status][Discuss] Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. Input 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数

【bzoj3295】动态逆序对

我怎么控制不住自己又写了个数据结构啊--真是的-- 其实我是想练CDQ分治的--结果忍不住又写了个主席树. 首先看看不动态的逆序对咋做?树状数组嘛. 那么删除咋搞?就是考虑贡献,把它前面比他大的,后面比他小的减去-- 诶?带修改主席树?我--我好像才写过--? 1 #include<bits/stdc++.h> 2 #define inf 0x7fffffff 3 #define N 100005 4 #define M 5000005 5 using namespace std; 6 typ

[BZOJ3295][Cqoi2011]动态逆序对

试题描述 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数. 输入 输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数.以下n行每行包含一个1到n之间的正整数,即初始排列.以下m行每行一个正整数,依次为每次删除的元素. 输出 输出包含m行,依次为删除每个元素之前,逆序对的个数. 输入示例 5 4 1 5 3 4 2 5 1 4 2 输出示例 5 2