我排第几个

我排第几个

时间限制:1000 ms  |  内存限制:65535 KB

难度:3

输入

第一行有一个整数n(0<n<=10000);
随后有n行,每行是一个排列;

输出

输出一个整数m,占一行,m表示排列是第几位;

样例输入

3
abcdefghijkl
hgebkflacdji
gfkedhjblcia

样例输出

1
302715242
260726926

来源

[苗栋栋]原创

上传者

苗栋栋

描述

现在有"abcdefghijkl”12个字符,将其所有的排列中按字典序排列,给出任意一种排列,说出这个排列在所有的排列中是第几小的?

康托展开

  康托展开的公式是 X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! 
其中,ai为当前未出现的元素中是排在第几个(从0开始)。
  这个公式可能看着让人头大,最好举个例子来说明一下。例如,有一个数组 
s = ["A", "B", "C", "D"],它的一个排列 s1 = ["D", "B", "A", "C"],
现在要把 s1 映射成 X。n 指的是数组的长度,也就是4,所以X(s1) = a4*3! + a3*2! + a2*1! + a1*0!
关键问题是 a4、a3、a2 和 a1 等于啥?
a4 = "D" 这个元素在子数组 ["D", "B", "A", "C"] 中是第几大的元素。
"A"是第0大的元素,"B"是第1大的元素,"C" 是第2大的元素,"D"是第3大的
元素,所以 a4 = 3。
a3 = "B" 这个元素在子数组 ["B", "A", "C"] 中是第几大的元素。"A"是
第0大的元素,"B"是第1大的元素,"C" 是第2大的元素,所以 a3 = 1。
a2 = "A" 这个元素在子数组 ["A", "C"] 中是第几大的元素。"A"是第0大
的元素,"C"是第1大的元素,所以 a2 = 0。
a1 = "C" 这个元素在子数组 ["C"] 中是第几大的元素。"C" 是第0大的元素
,所以 a1 = 0。(因为子数组只有1个元素,所以a1总是为0)
所以,X(s1) = 3*3! + 1*2! + 0*1! + 0*0! = 20

举例说明

起始是:abcdefghijkl;

想要变成hgebkflacdji;

首先第一个字符由a变成h,就要知道它是第8个字符,已经经历过7次11的阶乘变化才能得到h,依次类推;

S=7*11!+6*10!+4*9!+1*8!+10*7!+5*6!+11*5!+0*4!+2*3!+3*2!+9*1!+8*0!=302715242;
#include<stdio.h>
int main()
{
	int t,jc[15];
	jc[0] = 0,jc[1] = 1;
	for (int i=2;i<12;i++)//储存0~11的阶乘 
		jc[i] = jc[i-1]*i;
	scanf("%d",&t);
	while (t--)
	{
		char s[15];
		int i,j;
		getchar();//接受多余字符 
		scanf("%s",s);
		int sum = 0;
		for (i=0;i<12;i++)
		{
			int cnt = 0;//计数清零 
			for (j=i+1;j<12;j++)
				if (s[j]<s[i])
					cnt++;//统计按照顺序这是第几个字符 
			sum += cnt * jc[11-i];//要排列到本字符需要经历的次数
		}
		printf("%d\n",sum+1);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40912854/article/details/81189487