三字符字典内的序号与字符串互查 - 进制转换

SIGMA={a,b,c}  SIGMA* is based on SIGMA with these rules:

1. SIGMA ⊆ SIGMA*

2. if s1∈SIGMA*, s2∈ SIGMA*, then s1s2∈SIGMA*

3. Any element of SIGMA* can be formed within finite application of rule 1) 2)


The elements in SIGMA* are firstly ordered by length (short to long), and alphabetically ordered when of the same length.

Design an algorithm to solve (empty string is ordered 0):

1) given a string alpha, find the sequence number

2) given a sequence number, find alpha


给定seq求alpha相对比较麻烦:

离散数学课上的一个思考题,把a b 和c理解为数字0 1 和2,SIGMA*集合实际上是一个允许有前0的三进制无符号整数有序集合,其标号从1开始,长度l的最小数字L_l=(3^0+3^1+...+3^(l-1)),任意给定序号seq求长度len,可以令L_l大于seq解出长度len等于log_3(2*seq+1)的整数部分。求出长度后将seq与在这个长度下的最小数的序号相减得到leap,接下来就是从大到小每一位上把leap除以这个位对于的3的那个次方,得到整数部分就是这个位与a的差距了,然后将leap减去用这个位抵消的部分,循环直到个位被完成。


给定alpha求seq很简单,按位(a是1,b是2,c是3)乘上对应的3的那个次方,加起来就行了


这个题目某种程度上揭露了一些允许有前0的集合以及不允许有前0的集合的区别:

不允许前0的集合有一特点,那就是如果规定'1'是第1个元素,那么按照长度+字典序排序(正如本题叙述的),每个数字的大小也正好等于其序号。这里数字的大小指的是:这个字符串代表的数字,其各位上的单个数乘以这个位在进制内对应的幂再求和,例如十进制的123等于1*100+2*10+3*1。这对于任意k进制都成立,用等比级数的部分和公式很简单可以证明(规定长度为0的字符串只有1个'0',长度1有(k-1)个,长度i的有(k-1)*k^(i-1)个,因为可以增加(k-1)个数字在最前端);在这样的集合中给定一个字符串的序号就知道其大小,我要得到其长度只直接对序号取对数再取整就行了。

但是由于允许前0的存在,同样的数字大小计算方法得到的就不是其序号了,如果想要达到这个目的,就需要改变计算方法。如本题所述规定'0'是第1个元素的话,每个数字的'大小'应当其各位上的单个数的序号乘以这个位在进制内对应的幂再求和。例如三进制的012,0的序号为1,1为2,2为3,012=1*9+2*3+3*1。对应着幂依旧成立是因为这位后面的位的组合方法依旧是那么多,但是由于0开始就表示了有1个这个位,所以要改成序号。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
using namespace std;
string alpha;
int seq=0;

void findseq()
{
	int len = alpha.length();
	for (int i = 0; i < len; i++)
		seq += (alpha[i]-96) * pow(3, len - i - 1);
}

void findalpha()
{
	if (seq == 0) return;
	int len = log(2*seq+1)/log(3);
	int leap = seq-int((pow(3,len)-3)/2)-1;

	for (int i = 0; i < len; i++)
	{
		int bitleap = leap / pow(3,len-i-1);
		alpha += 'a' + bitleap;
		leap -= pow(3, len - i - 1)*bitleap;
	}	
}

void solveseq(string tmp)
{
	for (int i = 0; i < tmp.length(); i++)
		seq += pow(10, tmp.length() - i - 1)*(tmp[i] - '0');

	findalpha();

	cout << alpha << endl;
}

void solvealpha(string tmp)
{
	alpha = tmp;
	
	findseq();
	cout << seq << endl;
}

int main()
{
	string tmp;
	cin >> tmp;
	if (tmp[0] >= 'a')
		solvealpha(tmp);
	else
		solveseq(tmp);
	return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值