2 条题解

  • 0
    @ 2025-10-8 16:58:02

    康托展开与逆康托展开实现

    程序实现了康托展开(将排列转化为字典序排名)和逆康托展开(将排名转化为排列),并处理多组查询。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    int a[21],n,m;
    
    LL d[21];
    LL  kangtuo()//把排列转化为整数:n个数的排列a是第几个排列(a排列的字典序)
    {
        bool bo[21];memset(bo,0,sizeof(bo));
        LL sum=0;
        for(int i=1;i<=n;i++)
        {
            int k=0;for(int j=1;j<a[i];j++)k=k+(bo[j]==0);//统计有多少个比a[i]小且没有出现过的数
            sum=sum+k*d[n-i];
            bo[a[i]]=1; 
        }
        return sum+1;//sum表示a排列之前有多少个排列   
    }
    void nikangtuo(LL sum)//把整数转化为排列
    {
        sum--;
        bool bo[21];memset(bo,0,sizeof(bo));
        for(int i=1;i<=n;i++)
        {
            int k=sum/d[n-i];
            sum=sum%d[n-i];
            int kk=0;
            for(int j=1;j<=n;j++)
            {
                if(bo[j]==0)
                {
                    kk++;
                    if(kk==k+1){a[i]=j;bo[j]=1;break;}
                }   
            }
        }
        for(int i=1;i<=n;i++)printf("%d ",a[i]);
        printf("\n");
    }
    int main()
    {
        d[0]=1;for(int i=1;i<=20;i++)d[i]=d[i-1]*i;
        cin>>n>>m;
        while(m--)
        {
            char c;cin>>c;
            if(c=='P')
            {
                LL sum;scanf("%lld",&sum);
                nikangtuo(sum);
            }
            else{
                for(int i=1;i<=n;i++)scanf("%d",&a[i]);
                printf("%lld\n",kangtuo());
            }
        }
        return 0;
    }
    
    • 1

    【模拟】康托展开及逆运算[USACO11FEB] Cow Line S

    信息

    ID
    1559
    时间
    1000ms
    内存
    128MiB
    难度
    10
    标签
    递交数
    8
    已通过
    3
    上传者