题目大意:给一段字符串,可以任意将其中两个字符进行交换,问最后所有的情况中按字典序排序的第k中情况是多少,如果没有就输出impossible;
题目解析:按位枚举,从高位枚举,如果在当前位置后面的情况>=k,说明那个位肯定是正确的了,再枚举下一位,反之,将当前为的cur+1;
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
typedef long long ll;
ll fact[21];
int cnt[26];
char s[23];
void init()
{
fact[0]=fact[1]=1;
int i;
for(i=2;i<=20;i++)
fact[i]=fact[i-1]*i;
}
ll calu()
{
ll t=1;
int i,cntt=0;
for(i=0;i<26;i++)
{
cntt+=cnt[i];
t*=fact[cnt[i]];
}
return fact[cntt]/t;
}
bool dfs(int pos,int cur,int ans)
{
if(!cnt[cur]) return dfs(pos,cur+1,ans);
if(pos>=strlen(s+1)||cur>=26) return 1;
int i;
cnt[cur]--;
ll temp=calu();
if(temp>=ans)
{
printf("%c",'a'+cur);
dfs(pos+1,0,ans);
}
else
{
ans-=temp;
cnt[cur]++;
dfs(pos,cur+1,ans);
}
}
int main()
{
int cas,c,n,i;
scanf("%d",&cas);
init();
for(c=1;c<=cas;c++)
{
memset(cnt,0,sizeof(cnt));
scanf("%s",&s[1]);
scanf("%d",&n);
for(i=1;i<=strlen(s+1);i++)
cnt[s[i]-'a']++;
if(n>calu())
{
printf("Case %d: Impossible\n",c);
continue;
}
printf("Case %d: ",c);
dfs(0,0,n);
printf("\n");
}
return 0;
}