我排第几个——康托展开

描述

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

输入
第一行有一个整数n(0<n<=10000);
随后有n行,每行是一个排列;
输出
输出一个整数m,占一行,m表示排列是第几位;
样例输入
3
abcdefghijkl
hgebkflacdji
gfkedhjblcia
样例输出
1
302715242

260726926

给大家说下什么叫康托展开

如 {1,2,3} 按从小到大排列一共6个:123 132 213 231 312 321。想知道321是{1,2,3}中第几个大的数。

这样考虑:第一位是3,小于3的数有1、2 。所以有2*2!个。再看小于第二位,小于2的数只有一个就是1 ,所以有1*1!=1 所以小于32

的{1,2,3}排列数有2*2!+1*1!=5个。所以321是第6个大的数。2*2!+1*1!是康托展开。

再举个例子:1324是{1,2,3,4}排列数中第几个大的数:第一位是1小于1的数没有,是0个,0*3!,第二位是3小于3的数有1和2,但1已经在第一位了,所以只有一个数2,1*2! 。第三位是2小于2的数是1,但1在第一位,所以有0个数,0*1!,所以比1324小的排列有0*3!+1*2!+0*1!=2个,1324是第三个大数

#include<iostream>
#include<stdio.h>
using namespace std;
int f(int n);
long long KT(int n,int b[],long long f[]);
int main(void){
	long long f[13];
	f[0]=1;
	for(long long i=1;i<13;i++)
	f[i]=f[i-1]*i;
	int s;
	cin>>s;
	while(s--){
		char a[12];
		int a1[12];
		scanf("%s",a);
		for(int i=0;i<12;i++)
		  a1[i]=(int)(a[i]-96);
		  cout<<KT(12,a1,f)<<endl;
	}
	
}
int f(int n){
	long long s=1;
	for(int i=1;i<=n;i++)
	s=s*i;
	return s;
}
long long KT(int n,int b[],long long f[]){
	int i,j,t;
	long long sum=0;
	for(i=0;i<n;i++){
		t=0;
		for(j=i+1;j<n;j++)
		if(b[j]<b[i])
		t++;
		sum+=t*f[n-i-1];
	}
	return sum+1;
}


你可能感兴趣的:(算法,竞赛,康拓展开)