我排第几个
时间限制: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;
}