LightOJ 1060-第k个排列【数学+模拟】 难度:***

题意:

Given a string of characters, we can permute the individual characters to make new strings. At first we order the string into alphabetical order. Then we start permuting it.

For example the string ‘abba’ gives rise to the following 6 distinct permutations in alphabetical order.

aabb 1

abab 2

abba 3

baab 4

baba 5

bbaa 6

Given a string, you have to find the nth permutation for that string. For the above case ‘aabb’ is the 1st and ‘baab’ is the 4th permutation.

Input
Input starts with an integer T (≤ 200), denoting the number of test cases.

Each case contains a non empty string of lowercase letters with length no more than 20 and an integer n (0 < n < 231).

Output
For each case, output the case number and the nth permutation. If the nth permutation doesn’t exist print ‘Impossible’.

Sample Input
3
aabb 1
aabb 6
aabb 7
Sample Output
Case 1: aabb
Case 2: bbaa
Case 3: Impossible

题解:

注意:不能使用next_permutation函数来解此题,因为一个一个找一定会超过时间限制。
这个其实是逆康托展开,只不过难度再大一点,因为这里有重复字符。
首先先举无重复字符的例子,比如abcd。当a作为第一个时,一共有(4-1)!种情况,然后和答案进行对比,如果答案<3!则a是第一个字符,若不是则换下一个字符,因为就20个字符所以暴力找就行。
对于有重复字符的,比如abbbccc,当a作为第一个字符后,一共的情况数是6!/(3!×3!) ,对于学过排列组合的朋友们可以写成A66/(A33×A33)其实就是排除相同字符内部排序的影响,再重复上面的操作就行。

代码:

#include<stdio.h>
#include<string.h>
const int word=26;
long long jiecheng(int a)
{
	if(a==0)return 1;
	long long sum=1;
	for(int i=2;i<=a;i++)sum*=i;
	return sum;
}
int main()
{
	int t,n,len,count[word],stalen;
	long long temp,max;
	char ch[22];
	scanf("%d",&t);
	for(int l=1;l<=t;l++)
	{
		for(int i=0;i<word;i++)count[i]=0;
		scanf("%s%d",ch,&n);
		len=strlen(ch);
		max=jiecheng(len);
		for(int i=0;i<len;i++)count[ch[i]-'a']++;
		for(int i=0;i<word;i++)if(count[i])max/=jiecheng(count[i]);
		if(n>max)printf("Case %d: Impossible\n",l);
		else
		{
			printf("Case %d: ",l);
			stalen=len;
			for(int i=0;i<stalen;i++)
			{
				for(int j=0;j<word;j++)
				{
					if(!count[j])continue;
					count[j]--;
					temp=jiecheng(len-1-i);
					for(int k=0;k<word;k++)if(count[k])temp/=jiecheng(count[k]);
					if(temp>=n)
					{
						printf("%c",'a'+j);
						break;
					}
					else
					{
						count[j]++;
						n-=temp;
					}
				}
			}
			printf("\n");
			max=0;
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值