全排列与逆序数的组合

之前也做过这类题,现在做又忘了,整理一下。
ACM中遇到逆序数最多的就是 全排列+逆序数

引入

这样一题:
给出n个数字,求使用冒泡排序所需要交换的次数(n到5e5)(POJ2299)

问题可以转化为求逆序数。
不多解释,一般有两种方法。
一:线段树或树状数组(树状数组本身就是线段树的变式)(这里不是重点,略过)
二:归并排序。
下面归并排序模板(需要一个辅助数组)

int b[maxn];
void ms(int l,int r){
    
    
	if(l==r)	return;
	int mid=(l+r)>>1;
	ms(l,mid);	ms(mid+1,r);
	int x=l,y=mid+1;
	for(int i=l;i<=r;i++){
    
    
		if(y>r||(x<=mid&&a[x]<=a[y]))	b[i]=a[x++];
		else	b[i]=a[y++];
	}
	for(int i=l;i<=r;i++)	a[i]=b[i];
}

而这题:

int b[maxn];
int ms(int l,int r){
    
    
	if(l==r)	return;
	int mid=(l+r)>>1;
	int ans=ms(l,mid)+ms(mid+1,r);
	int x=l,y=mid+1;
	for(int i=l;i<=r;i++){
    
    
		if(y>r||(x<=mid&&a[x]<=a[y]))	b[i]=a[x++];
		else{
    
    
			b[i]=a[y++];
			ans+=mid-x+1;	//区别 
		}
	}
	for(int i=l;i<=r;i++)	a[i]=b[i];
	return ans;
}

但今天不止于此,还看了其他定理。

正文

一些详细证明在下面这个博客:链接(这很重要)

一、根据逆序数求排列数

问题:给定一个n元排列,它的逆序数存在且唯一。那么反过来,已知一个n元排列的逆序数为m,这样的n元排列有多少种?

分析:我们用f(n,m)表示逆序数为m的n元排列的个数,则求满足条件的排列个数问题就转化为求f(n,m)的值的问题。

为了得到最终结果,我们先研究f(n,m)的性质。可以得到以下几个命题:

[命题1] 对任意n>=2且0<=m<=C(n,2)时f(n,m)>=1;当m>C(n,2)时,f(n,m)=0

[命题2] f(n,m)=f(n,C(n,2)-m)

[命题3] f(n+1,m)=f(n,m)+f(n,m-1)+…+f(n,m-n)

[命题4] f(n,0)=f(n,C(n,2))=1
[命题5] f(n,1)=f(n,C(n,2)-1)=n-1(n>1)
[命题6] f(n,2)=f(n,C(n,2)-2)=C(n,2)-1(n>2)

同理递推下去

f(n,3)=C(n,3)-C(n,2)-C(n,1) (n>3)

f(n,4)=C(n,4)+2C(n,3)-C(n,1) (n>4)

f(n,5)=C(n,5)+3C(n,4)+2C(n,3)-C(n,2)+1 (n>5)

我们可以无限递推下去,计算f(n,k)的时候要用到前面所推导出的f(n,1)~f(n,k-1)。但是却很难得到一个通项公式。这个问题就类似于用∑(k ^ t - (k-1) ^ t) 来求∑(k ^ (t-1)),每作下一项都要用到前面所有的结果。

二、根据每个数的逆序数,然后求出原排列

找题解中

三、给定逆序数,求满足此逆序数的最小排列

定理1:

对于一个形如1,2,3,…,i-1,i,n,…i+1的排列q(如n=5时的1,2,5,4,3),即在数n前保证首项为1且严格以公差为1递增而数n之后排列任意的数列,

(1)当数n之后是递减的时候q的逆序数最多,为t=C(n-i,2)。
(2)排列q是出现逆序数为t的最小排列。

定理2

在定理1所设定的排列q的基础上,我们将数n后面的第k小数与数n的前一个数(即i)交换,然后使数n后面保持逆序。这样得到的新排列所含的逆序数为t=C(n-i,2)+k,且这个排列是逆序数为t的最小排列。

解题:

有了这两个命题作基础,我们很容易就能够得到这道题的算法。首先利用定理1,二分查找找到数n的位置,我们可以得到数n在这个位置的时候形如q的排列的逆序数t。然后计算t与m的差值,得出k,然后根据定理2进行变换,最后得出要求的排列。

猜你喜欢

转载自blog.csdn.net/weixin_45606191/article/details/108982301
今日推荐