1. 程式人生 > >我排第幾個——康託展開

我排第幾個——康託展開

描述

現在有"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;
}