康托展开 已知一个排列,求这个排列在全排列中是第几个 康托展开逆运算:已知在全排列中排第几,求这个排列

本文介绍了一种用于计算排列在全排列中字典序位置的算法——康托展开,并提供了正逆运算的代码实现。该算法适用于处理特定的排列组合问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

The isolated people of MacGuffin Island have a unique culture, and one of the most interesting things about them is their language. Their alphabet consists of the first 9 letters of the Roman alphabet (a, b, c, d, e, f, g, h, i). All of their words are exactly 9 letters long and use each of these 9 letters exactly once. They have a word for every possible permutation of these letters. In the library of their most sacred temple is a dictionary, and each word in their language has its own page. By coincidence they order their words exactly as they would be in ordered in English, so the word ‘abcdefghi’ is on the first page, and the word ‘ihgfedcba’ is on the last. The question is, given a list of random words from the MacGuffin language, can you say on which page of the MacGuffin dictionary each appears?

Input

The first line of the input file is a positive integer. This integer tells you how many words will follow. The upper limit for this number is 6000. Every subsequent line contains a single word from the MacGuffin language, so if the first number is 1000 there will be 1000 lines after it, each containing a single word.

Output

Each line of output will contain an integer. This integer should be the page number for the corresponding word.

Sample Input

4
abcdefgih
abcdefghi
abcdefgih
ihgfedcba

Sample Output

2
1
2
362880

康托展开的大意就是一个排列在它的全排列中按字典序排序时所处位置

比如213,它的全排列有123、132、213、231、312、321(已按字典序排好),

所以它的康托展开为2,没错是2,因为康托展开是从0开始计数

的,所以学长教我们一个新的记法——康托展开的大小即为在此排列前存在的排列的个数。

求法自然有公式的呀——       

表示第i个元素在未出现的元素中排列第几,n的大小为字符串的长度

比如213这个例子,n=3,然后2排第1,所以a3=1,1排第0,所以a2=0,3排第2,所以a3=2,所以

ans=1*2+0*1+2*0=2

 

 

#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
int f[10];
void init()
{
    f[1]=1;
    for(int i=2;i<10;i++)
        f[i]=f[i-1]*i;
}
int main()
{
    int N,M;
    char s[10];
    init();
    scanf("%d",&N);
    while(N--)
    {
        int ans=0;
        scanf("%s",s);
        for(int i=0;i<9;i++)
        {
            int temp=0;
            for(int j=i+1;j<9;j++)
                if(s[j]<s[i])temp++;
            ans+=temp*f[9-i-1];
        }
        printf("%d\n",ans+1);
    }
    return 0;
}

 

康托展开的逆运算:就是根据某个排列的在总的排列中的名次来确定这个排列。比如:

求1234所有排列中排第20的是啥,那么就利用辗转相除法确定康托展开中的系数,然后每次输出当前未出现过的第个元素。

代码实现康托展开逆运算:

 

 

 

 

//康托展开逆运算  
void Work(LL n,LL m)  
{  
    n--;  
    vector<int> v;  
    vector<int> a;  
    for(int i=1;i<=m;i++)  
        v.push_back(i);  
    for(int i=m;i>=1;i--)  
    {  
        LL r = n % f[i-1];  
        LL t = n / f[i-1];  
        n = r;  
        sort(v.begin(),v.end());  
        a.push_back(v[t]);  
        v.erase(v.begin()+t);  
    }  
    vector<int>::iterator it;  
    for(it = a.begin();it != a.end();it++)  
        cout<<*it;  
    cout<<endl;  
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值