zoukankan      html  css  js  c++  java
  • 奇数码问题(求证明)

    题意

    题意

    题解

    艹,推逆序对推错了,艹

    咳咳,依旧是两种做法。

    做法1

    考虑把整个图化成一条数列。(第二行拼到第一行后面,以此类推)

    考虑整个图的逆序对数((0)也考虑上)。

    左右交换会使逆序对数(+/-1),那么上下交换呢?

    由于(0)比所有数字都要小,所以肯定会(+-n)

    那么(x)在数列和中间的(n-1)个数字会产生多少个逆序对数呢,假设少了(q)个逆序对,多了(p)个逆序对?

    那么(q+p)为偶数,(p-q)必定为偶数,又因为(n)为奇数,所以上下交换也是一个奇数。

    那岂不是意味着每次交换逆序对数就会改变,那拿什么判断呢?

    但是不难发现(0)的移动也是个奇数,两个一加就是偶数,所以只需要把整个图的逆序对数加上(0)的位置即可。

    但是至于为什么奇偶性质相同一定能到达,我也不知道,求证明。

    #include<cstdio>
    #include<cstring>
    #define  N  510000
    using  namespace  std;
    int  bst[N];
    int  a[N],b[N],nn;
    inline  int  lowbit(int  x){return  x&-x;}
    void  ins(int  x)
    {
    	while(x<=nn)
    	{
    		bst[x]++;
    		x+=lowbit(x);
    	}
    }
    int  findans(int  x)
    {
    	int  ans=0;
    	while(x>=1)
    	{
    		ans+=bst[x];
    		x-=lowbit(x);
    	}
    	return  ans;
    }
    int  n;
    int  main()
    {
    	while(scanf("%d",&n)!=EOF)
    	{
    		memset(bst,0,sizeof(bst));
    		nn=n*n;
    		int  t=0;
    		long  long  an1=0,an2=0;
    		for(int  i=1;i<=n;i++)
    		{
    			for(int  j=1;j<=n;j++)
    			{
    				scanf("%d",&a[t+j]);
    				a[t+j]++;
    				if(a[t+j]==1)an1+=t+j;
    			} 
    			t+=n;
    		}
    		for(int  i=1;i<=nn;i++)
    		{
    			an1+=i-1-findans(a[i]);ins(a[i]);
    		}
    		memset(bst,0,sizeof(bst));
    		t=0;
    		for(int  i=1;i<=n;i++)
    		{
    			for(int  j=1;j<=n;j++)
    			{
    				scanf("%d",&a[t+j]);
    				a[t+j]++;
    				if(a[t+j]==1)an2+=t+j;
    			} 
    			t+=n;
    		}
    		for(int  i=1;i<=nn;i++)
    		{
    			an2+=i-1-findans(a[i]);ins(a[i]);
    		}
    		if((an1&1)==(an2&1))printf("TAK
    ");
    		else  printf("NIE
    ");
    	}
    	return  0;
    }
    

    做法2

    参考

    判断忽略(0)之后的逆序对数是否相同,相同则可以到达,反之不能。

    推法和上面差不多,我就不说了。

    #include <bits/stdc++.h>
    using namespace std;
    const int N=510;
    int n,m,a[N*N],b[N*N],c[N*N],i,j,k;
    long long cnt;
    void merge(int a[],int l,int r)
    {
        if (r-l<1)
            return ;
        int mid=(l+r)>>1;
        merge(a,l,mid);
        merge(a,mid+1,r);
        int i=l,j=mid+1;
        for (int k=l; k<=r; k++)
        {
            if (j>r || i<=mid && a[i]<=a[j])
                b[k]=a[i++];
            else
            {
                cnt+=mid-i+1;
                b[k]=a[j++];
            }
        }
        for (int k=l; k<=r; k++)
            a[k]=b[k];
    }
    signed main()
    {
        ios::sync_with_stdio(false);
    //  freopen("stdin.in","r",stdin);
    //  freopen("stdout.out","w",stdout);
        while(cin>>n)
        {
            int ok=0,x;
            for (i=1; i<=n*n; i++)
            {
                cin>>x;
                if (x==0)
                    ok=1;
                else
                    a[i-ok]=x;
            }
            ok=0;
            for (i=1; i<=n*n; i++)
            {
                cin>>x;
                if (x==0)
                    ok=1;
                else
                    c[i-ok]=x;
            }
            cnt=0;
            memset(b,0,sizeof(b));
            merge(a,1,n*n);
            long long ans=cnt;
            memset(b,0,sizeof(b));
            cnt=0;
            merge(c,1,n*n);
            if ((ans&1)==(cnt&1))
                puts("TAK");
            else
                puts("NIE");
        }
        return 0;
    }
    
    作者:秦淮岸灯火阑珊已退役
    链接:https://www.acwing.com/solution/content/847/
    来源:AcWing
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    
  • 相关阅读:
    Java反射在Android中的使用
    配置adb环境变量
    Android Studio 生成Release版,报Warning的解决办法
    Android Studio导入System Library步骤
    Windows 10 Java环境变量配置
    做一个有内涵的程序猿
    简述Python2与Python3的区别
    对不起,您输入的内容不合法
    python的数据类型
    python三器——装饰器/迭代器/生成器
  • 原文地址:https://www.cnblogs.com/zhangjianjunab/p/13409377.html
Copyright © 2011-2022 走看看