lightoj 1060 - nth Permutation 组合数学

来源:互联网 发布:car软件 编辑:程序博客网 时间:2024/06/06 09:22

给定一个字符串和k,求字符串第k大字典序的排列...

康拓逆展开...可以求没有重复元素的第k个排列,有重复的话,方法是一样的,只是求解方案数变了。

由单纯的阶乘变为len!/cnt[i]!(0<=i<26),cnt[i]为第i个字母出现的次数。

而且某一位要放置的字母出现多次,那么只需要计算一次就好,因为所有的排列都是一模一样的。

#include<bits/stdc++.h>using namespace std;#define inf 0x7fffffff#define ll long longchar s[22];int a[28];ll f[23];int main(){    int t;    f[0]=1;    for(int i=1;i<=22;i++) f[i]=f[i-1]*i;    scanf("%d",&t);    for(int cas=1;cas<=t;cas++)    {        int n;        scanf("%s %d",s,&n);        int len=strlen(s);        memset(a,0,sizeof(a));        for(int i=0;i<len;i++)        {            a[s[i]-'a']++;        }        ll zs=f[len];        for(int i=0;i<26;i++) zs/=f[a[i]];        printf("Case %d: ",cas);        if(zs<n)        {            puts("Impossible");            continue;        }        for(int i=0;i<len;i++)//当前第i位选择那个字母        {            for(int j=0;j<26;j++)//第i个字母为j            {                if(a[j]==0) continue;                a[j]--;//假如第j个字母做在第i个位置的总排列情况为tmp种                ll tmp=f[len-i-1];                for(int k=0;k<26;k++)                    tmp/=f[a[k]];                if(n<=tmp)//如果方案数已经超过n,那么肯定这一位字母是第j个                {                    printf("%c",'a'+j);                    break;                }                n-=tmp;//否则肯定是下一个字母的排列                a[j]++;            }        }        printf("\n");    }    return 0;}


0 0
原创粉丝点击