奇数码问题(逆序对求解)

两个矩阵,排成线性序列,若逆序对奇偶性相同,则可以互相转化矩阵

注意:0不算入内,

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

typedef long long ll;

const ll nil=20000000000;
const int maxn=500000+10;
ll L[maxn/2],R[maxn/2];
int n;
ll a[maxn];
int top;

ll megersort(int l,int r,int mid,ll a[]){
   int n1=mid-l;
   int n2=r-mid;
   ll cnt=0;
   int i,j;
   for (i=0;i<n1;i++) L[i]=a[l+i];
   for (j=0;j<n2;j++) R[j]=a[mid+j];
   L[n1]=nil;
   R[n2]=nil;
   i=j=0;
   for (int k=l;k<r;k++){
        if(L[i]<=R[j]){
            a[k]=L[i++];
        }
        else {
            a[k]=R[j++];
            cnt=((cnt%2)+(mid+j-k-1)%2)%2;
        }
   }
  return cnt%2;
}

ll meger(int l,int r,ll a[]){
   if(l+1<r){
    int mid=(l+r)>>1;
    ll v1=meger(l,mid,a);
    ll v2=meger(mid,r,a);
    ll v3=megersort(l,r,mid,a);
    return (v1%2+v2%2+v3%2)%2;
   }
   else return 0;
}

int main(){
    while(scanf("%d",&n)!=EOF){
    memset(R,0,sizeof(R));
    top=-1;
    int x;
    for (int i=1;i<=n;i++){
        for (int j=1;j<=n;j++){
          scanf("%d",&x);
          if(x!=0) a[++top]=x;
        }
    }
    ll ans1=meger(0,top+1,a);
    memset(a,0,sizeof(a));
    memset(L,0,sizeof(L));
    memset(R,0,sizeof(R));
    top=-1;
    for (int i=1;i<=n;i++){
        for (int j=1;j<=n;j++){
          scanf("%d",&x);
          if(x!=0) a[++top]=x;
        }
    }
    ll ans2=meger(0,top+1,a);
    if(ans1%2==ans2%2) printf("TAK\n");
    else printf("NIE\n");
    //printf("%lld %lld\n",ans1,ans2);
    }
return 0;
}

原文地址:https://www.cnblogs.com/lmjer/p/8893112.html

时间: 2024-10-12 22:09:42

奇数码问题(逆序对求解)的相关文章

CH Round #72 奇数码问题[逆序对 观察]

描述 你一定玩过八数码游戏,它实际上是在一个3*3的网格中进行的,1个空格和1~8这8个数字恰好不重不漏地分布在这3*3的网格中. 例如:5 2 81 3 _4 6 7 在游戏过程中,可以把空格与其上.下.左.右四个方向之一的数字交换(如果存在).例如在上例中,空格可与左.上.下面的数字交换,分别变成:5 2 8       5 2 _      5 2 81 _ 3       1 3 8      1 3 74 6 7       4 6 7      4 6 _ 奇数码游戏是它的一个扩展,

POJ 2299 逆序对

Crossings Time Limit: 2 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100463 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent

poj2299--归并排序求解逆序对

1.题目链接 http://acm.hrbust.edu.cn/vj/index.php?c=problem-problem&id=166400 2.代码: //归并排序求解逆序对 #include<iostream> #include<stdio.h> #include<math.h> #include<algorithm> #include<stack> #include<queue> #include<string

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

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

AcWing:108. 奇数码问题(归并排序 + 逆序数)

你一定玩过八数码游戏,它实际上是在一个3×3的网格中进行的,1个空格和1~8这8个数字恰好不重不漏地分布在这3×3的网格中. 例如: 5 2 8 1 3 _ 4 6 7 在游戏过程中,可以把空格与其上.下.左.右四个方向之一的数字交换(如果存在). 例如在上例中,空格可与左.上.下面的数字交换,分别变成: 5 2 8 5 2 _ 5 2 8 1 _ 3 1 3 8 1 3 7 4 6 7 4 6 7 4 6 _ 奇数码游戏是它的一个扩展,在一个nn×nn的网格中进行,其中nn为奇数,1个空格和1

Bestcoder7(1004)hdu4988(经典问题:树状数组套treap求解动态逆序对)

Little Pony and Boast Busters Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 83    Accepted Submission(s): 32 Problem Description "I hereby challenge you, Ponyvillians: anything you can do

归并算法实现求解逆序对【模板】

已用此模板过掉了好几题. #include<stdio.h> #define LL long long //以后可以考虑这样写 简洁 int n,i,a[500010], b[500010]; //需要开辟两个数组 LL count(int l,int r)//统计[l ,r]的逆序对数 { LL s=0;//初始化 int mid=(l+r)/2, i=l, j=mid+1, k=l; //printf("%d \n", mid ); if (l<mid) s+=c

逆序对的数量(归并排序求解)

给定一个长度为n的整数数列,请你计算数列中的逆序对的数量. 逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i < j 且 a[i] > a[j],则其为一个逆序对:否则不是. 输入格式 第一行包含整数n,表示数列的长度. 第二行包含 n 个整数,表示整个数列. 输出格式 输出一个整数,表示逆序对的个数. 数据范围 1≤n≤1000001≤n≤100000 输入样例: 6 2 3 4 5 6 1 输出样例: 5 import java.util.Scanner; public

奇数码问题

奇数码问题 有一个\(n\times n\)的网格图,网格由\(0\sim n-1\)组成,现在你可以进行操作,每次操作选择0与其相邻的位置上的数交换位置,给出两个网格图的初始局面,询问这两个局面是否能够互相到达,\(n\in\text{奇数},1\leq n\leq 500\). 解 此题套结论即可,但是不清楚结论,可以参考我的八数码的总结,但是我至今没有它的完整的证明,网上有一篇,但是我看不懂. 因为n是奇数,于是能够互相到达,当且仅当网格图拆行成列后形成的序列的不考虑0的逆序对个数奇偶性相