2021-07-12

康托展开

康托展开就是求一个字符串的字典序是这一串字符串的字符能组成的字符串中的第几名。(从小到大排列)。

时间复杂度
康托算法能在O(n2)的时间里求出该字典序的排名,用线段树维护的话能减少到O(nlogn)。

康拓展开的式子
在这里插入图片描述

int jc[10];//表示i的阶乘
jc[0]=1,jc[1]=1;
for(int i=2;i<10;i++){
	jc[i]=jc[i-1]*i;
}
int cantor(char s[])
{
	int ans=0,num=0;
	int len=strlen(s);
	for(int i=0;i<len;i++){
		num=0;
		for(int j=i+1;j<len;j++){
			if(s[i]>s[j])
				num++;
		}
		ans+=num*jc[len-1-i];
	}
	return ans;
}

ai表示的是,倒数第个i位置后面的数比倒数第i个位置的数小的个数。
即x则为这个字符串的排名-1,因为字典序最小的x为0。

为什么这个式子能求出排名

用 45231作为例子。
4后面比4小的数有 2 3 1。那么吧这三个数和4进行交换,那么后面4个数字随便排列都比之前的字典序要大,所以则是 3*(5-1)! ,以此类推。

逆康托展开

因为[an*(n-1)!]是绝对大于a(n-1)*(n-2)!的,所以我们求一个字符串的第x名的这个字符串。
就可以根据该公式来求,因为字典序最小时X为0,所以应该是求x-1.
即先求(x-1)/(n-1)!等于多少,即倒数第个i位置后面的数比倒数第i个位置的数小的个数。就可以根据这个个数,找到该位置的值。
如求一个长度为5的由12345组成的字符串的第55名,先求55/24=2,此时还未确定位置的数为 1 2 3 4 5 ,那么大于2个数的数为3,则第一个位置的数为3。
因为这个数确定了位置,那么接下来需要确定位置的数为 1 2 4 5。
需要求这个字符串的第55-4!*2名.

void decantor(int x, int n)
{
    vector<int> rest;  // 存放当前可选数,保证有序
    vector<int> ans;  // 所求排列组合
    for(int i=1;i<=n;i++)
        rest.push_back(i);
    sort(rest.begin(),rest.end());
    for(int i=n;i>=1;i--)
    {
        int r = x % jc[i-1];
        int t = x / jc[i-1];
        x = r;
        ans.push_back(v[t]);      // 剩余数里第t+1个数为当前位
        rest.erase(v.begin()+t);   // 移除选做当前位的数
    }
}

刷题
https://www.luogu.com.cn/problem/P2730
https://vjudge.net/contest/441637#problem/U
https://vjudge.net/contest/441637#problem/S
https://vjudge.net/contest/441637#problem/H
题解
github题解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值