南阳139 我是第几个(康托排序)和南阳143 第几是谁(康托逆排序)

我排第几个

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 3
描述

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

输入
第一行有一个整数n(0<n<=10000);
随后有n行,每行是一个排列;
输出
输出一个整数m,占一行,m表示排列是第几位;
样例输入
3
abcdefghijkl
hgebkflacdji
gfkedhjblcia
样例输出
1
302715242
260726926
/*
康拓展开     发现忘光了
Tme:2014-8-28 12:43
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long f[14]={1,1};
void factorial(){
	for(int i=2;i<=13;i++)
	f[i]=f[i-1]*i;
}
long long cantor(char *s){
	long long ans=0;
	int l=strlen(s);
	for(int i=0;s[i];i++){
		int num=0;
		for(int j=i;s[j];j++){
			if(s[j]<s[i])
			num++;
		}
		ans+=num*f[l-i-1];//阶乘表示的是 比它小的那个数 后边的阶乘 
		//每次加上比它小的个数与后边数的阶乘的乘积 比如  7 5 4 3 6 2 
		//第2个数 5 比它小的有 4 3 2 三个 以4为第二位 可构成的排列为 N! N表示 4 后边数字的个数
		//都比以5 为第二位的小 
		//所以总个数即为 num*N! 个  
	}
	return ans+1; //最后加 1 ,想半天没想明白,刚好筹出来 
}
void solve(){
	int T;
	factorial();
	scanf("%d",&T);
	char s[20];
	while(T--){
		scanf("%s",s);
		printf("%lld\n",cantor(s));
		
	}
}
int main(){
	solve();
return 0;
} 

<pre name="code" class="cpp">/*
逆康拓
Time:2014-8-28 12:45
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long f[20]={1,1,2,6};
void factorial(){
	for(int i=2;i<=13;i++)
		f[i]=f[i-1]*i;
}
void func (long long num){
	num--; //记得要减去1 
	int a[]={0,1,2,3,4,5,6,7,8,9,10,11,12};
	int ans[20],x;
	memset(ans,0,sizeof(ans));
	for(int i=0;i<=11;i++){
		 x=(int)num/f[11-i];//大数变小数容易出错,强制转换 
		//num=c1*1!+c2*2!……各个阶乘的与系数的乘积之和 
		//第一次取到11!的系数即第一位,阶乘与前边阶乘相差是数量级的,
		//直接除忽略掉小数就可以得到 
		//x表示之前有几个数,即取到的第几个数 
		ans[i]=a[x];//该数表示是第i位的数是多少,后边的阶乘会变成小数点后位数被忽略掉 
		for(int j=x;j<=11-i;j++)//把剩余的位数补上来 
			a[j]=a[j+1];//去掉取了的,往前移位 
		
		num-=x*f[11-i]; //减掉 取下一位 
	}
	for(int i=0;i<=11;i++)
	printf("%c",ans[i]+'a');
	printf("\n"); 
}
void solve(){
	factorial();
	int T;
	long long num;
	scanf("%d",&T);
	while(T--){
		int n;
		scanf("%lld",&num);
		//printf("%lld\n",f[n]);
		func(num);
	}
}
int main(){
	solve();
return 0;
} 


 
   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值