首页 > 编程语言 >第十三届蓝桥杯 C/C++ 大学 A 组 排列距离 康托和逆康托展开

第十三届蓝桥杯 C/C++ 大学 A 组 排列距离 康托和逆康托展开

时间:2024-04-04 11:04:50浏览次数:25  
标签:排列 int long 蓝桥 jie 逆康托 cheng 阶乘 康托

偏个题:算阶乘int可以到12,long long可以到20(12和20,好记)

背景知识

康托展开

原理

n个数字或者字符全排列(每个元素只用一次),从小到大按照字典序排列好,从0开始给他们编号,从字符串映射到编号就是康托展开。

从最高位向低位计算:

  1. 若取小于最高位的数字,则后面任意取都是小于这个排列的
  2. 若取相同数字,就比较下一位数字,若取小于的数后面同样任意排列,但是注意前面两个数字不能再用

总之,就是小于当前位的数字个数乘以剩下的元素的全排列

代码

#include<bitsstdc++.h>
 
/*******打出1-n的阶乘表*******/
int f[20];

void jie_cheng(int n)
{
    f[0] = f[1] = 1; // 0的阶乘为1
    for(int i = 2; i <= n; i++) f[i] = f[i - 1] * i;
}
 
/**************康托展开****************/

int kangtuo(string str)
{
    int ans = 1;  //注意,因为 12345 是算作0开始计算的,最后结果要把12345看作是第一个
    int len = str.length();
    for(int i = 0; i < len; i++){
        int tmp = 0;//用来计数的
 
        for(int j = i + 1; j < len; j++){
            if(str[i] > str[j]) tmp++;
            //计算str[i]是第几大的数,或者说计算有几个比他小的数
        }
 
        ans += tmp * f[len - i - 1];
    }
    return ans;
}
 
int main()
{
    jie_cheng(10);
    string str = "52413";
    cout<< kangtuo(str) << endl;
}

逆康托展开

原理

就是已知编号和元素,倒推出来原排列。

显然编号和原排列一一对应,是双射,所以必然可逆

举例:假设五个元素,序号为61.

用 61 / 4! = 2余13,说明两个元素小于2,说明比首位小的数有2个,所以第5位位为3。
用 13 / 3! = 2余1,说明a[4]=2,说明在第二位之后小于第二位的数有2个,所以第4位为4。
用 1 / 2! = 0余1,说明a[3]=0,说明在第三位之后没有小于第三位的数,所以第3位为1。
用 1 / 1! = 1余0,说明a[2]=1,说明在第二位之后小于第四位的数有1个,所以第2位为5。

通过以上分析,所求排列组合为 34152。

代码

#include<bits/stdc++.h>

using namespace std;
 
/*******打出1-n的阶乘表*******/
int f[20];
int x, num;
 
void jie_cheng(int n)
{
    f[0] = f[1] = 1; // 0的阶乘为1
    for(int i = 2; i <= n; i++) f[i] = f[i - 1] * i;
}
 
/**************康托逆展开**************/
 
vector<char> vec; //存需要排列的字符
void rev_kangtuo(int k) //输出序号为 k 的字符序列
{
    int n = vec.size(), len = 0;
    string ans = "";
    k--; // 算的时候是按 12345 是第0位
    for(int i = 1; i <= n; i++){
        int t = k / f[n - i]; // 第 i 位需要 第 t + 1 大的数
        k %= f[n - i];        //剩下的几位需要提供的排列数
        ans += vec[t] ; //  vec[t] 就是第 t + 1 大的数
        vec.erase(vec.begin() + t); 
//用过就删了,不用vector用暴力也可以,就是说枚举,然后一个一个的比较大小,并记录有几个没用过的字符且字典序比它小
    }
    cout << ans << '\n';
}
 
/***************************************/
// 假设展开后不超过10位
int main()
{
    jie_cheng(10); // 预处里好阶乘
    scanf("%d", &x); // 输入需要逆展开的数字
    /************康托逆展开***********/
    for(int i = 1; i <= 10; i++)
    {
    	if(x / f[i] == 0) // 求出 x 逆展开所需的最小的位数,方便下面的初始化
    	{
    		num = i;
    		break;
    	}
    }
    for(int i = 1; i <= num; i++) vec.push_back(i + '0'); //输入的位数只要不小于num就可以
    rev_kangtuo(x);
}

蓝桥杯题解代码

比较从上和下两个方向走的距离,取最小值

#include <bits/stdc++.h>
using namespace std;

/*******打出1-n的阶乘表*******/
long long f[25];
void jie_cheng(int n)
{
    f[0] = f[1] = 1; // 0的阶乘为1
    for(int i = 2; i <= n; i++) f[i] = f[i - 1] * i;
}
 
/**************康托展开****************/

int kangtuo(string str)
{
    long long ans = 1;  
    int len = 17;
    for(int i = 0; i < len; i ++ ) {
        int tmp = 0;//用来计数的
 
        for(int j = i + 1; j < len; j ++ ) {
            if(str[i] > str[j]) tmp ++ ;
            //计算str[i]是第几大的数,或者说计算有几个比他小的数
        }
 
        ans += tmp * f[len - i - 1];
    }
    return ans;
}
 
int main()
{
    jie_cheng(18);

    string str1 = "aejcldbhpiogfqnkr", str2 = "ncfjboqiealhkrpgd";
    long long n1 = kangtuo(str1);
    long long n2 = kangtuo(str2);
    long long sum1 = n2 - n1;
    long long sum2 = f[17] - sum1;
    long long sum = min(sum1, sum2);

    cout<< sum << endl;
}

标签:排列,int,long,蓝桥,jie,逆康托,cheng,阶乘,康托
From: https://blog.csdn.net/boomgloom/article/details/137369104

相关文章

  • 2015年蓝桥杯六届省赛大学B组真题
    2015年蓝桥杯六届省赛大学B组真题1.奖券数目 #include <iostream>using namespace std;int ans;bool check(int i){  while(i){    if(i%10==4)return false;    i/=10;  }  return true;}int main(){  int ans=0;  for(int i=10......
  • 2017省赛蓝桥杯B组
    2017省赛蓝桥杯B组5.购物单查看代码查看代码 #include<iostream>usingnamespacestd;intmain(){//请在此输入您的代码doublesum=180.90*0.88+10.25*0.65+56.14*0.9+104.65*0.9+100.30*0.88+297.15*0.5+26.75*0.65+130.62*0.5+240.28*0.58+270.62*0.8+115.8......
  • Luogu P8710 [蓝桥杯 2020 省 AB1] 网络分析 题解 [ 绿 ] [ 带权并查集 ]
    原题分析本题由于从一个节点发信息,同一个集合内的所有点都会收到信息,显然是一道要求维护各节点间关系的题,因此采用并查集的数据结构进行求解。但由于维护关系的同时还要维护权值,所以采用带权并查集,它是一种能维护某个节点与其祖宗节点之间关系的数据结构。带权并查集找父亲的......
  • 洛谷:P8671 [蓝桥杯 2018 国 AC] 约瑟夫环
    时间限制1.00s     内存限制256.00MB     难易度:普及+/提高【题目描述】n 个人的编号是1∼n,如果他们依编号按顺时针排成一个圆圈,从编号是 1 的人开始顺时针报数。(报数是从 1 报起)当报到 k 的时候,这个人就退出游戏圈。下一个人重新从 1 开始报......
  • 纯小白蓝桥杯备赛笔记--DAY9(搜索)
    文章目录三道例题学会DFS剪枝什么是剪枝数字王国之军训排队--2942特殊的三角形--3008特殊的多边形--3075DFS基础回溯简介回溯法模版例题N皇后--1508小朋友崇拜圈--182全球变暖--178记忆化搜索简介斐波那契数列混境之地5-3820地宫取宝-216三道例题学会DFS剪枝什......
  • 备战蓝桥杯之填空题技巧(持续更新)
    前言本刷题系列是我为了蓝桥杯前几天可以再系统性思考一下真题所做,所以部分内容会很简洁。如果能够帮助到你,我也会很开心!!!题目110.工作时长-蓝桥云课(lanqiao.cn)截图:excel解题:首先先点击数据排序,排好序后每两行进行计算,用后面的一行减去前面的一行,合并前两个单元格往......
  • 【洛谷 P8695】[蓝桥杯 2019 国 AC] 轨道炮 题解(映射+模拟+暴力枚举+桶排序)
    [蓝桥杯2019国AC]轨道炮题目描述小明在玩一款战争游戏。地图上一共有NNN个敌方单位,可以看作2D平面上的点。其中第i......
  • 【洛谷 P8672】[蓝桥杯 2018 国 C] 交换次数 题解(字符串+映射+全排列)
    [蓝桥杯2018国C]交换次数题目描述IT产业人才需求节节攀升。业内巨头百度、阿里巴巴、腾讯(简称BAT)在某海滩进行招聘活动。招聘部门一字排开。由于是自由抢占席位,三大公司的席位随机交错在一起,形如:ABABTATT,这使得应聘者十分别扭。于是,管理部门要求招聘方进行必要的......
  • 【洛谷 P8700】[蓝桥杯 2019 国 B] 解谜游戏 题解(字符串+映射+周期性)
    [蓝桥杯2019国B]解谜游戏题目背景题目描述小明正在玩一款解谜游戏。谜题由242424根塑料棒组成,其中黄色塑料棒4......
  • P8776 [蓝桥杯 2022 省 A] 最长不下降子序列
    1.首先想到的做法设up_len[i]为以a[i]为结尾的最长不下降子序列的长度,down_len[i]表示以a[i]为开始的最长不下降子序列的长度。在求pre的过程中记录下额外信息:down_pre[i]表示在求down_len[i]的过程中,i是由哪个点转移过来的;得到dp的转移方程:if(down_pre[i])ans......