题目描述
问题描述:
在数据加密和数据压缩中常需要对特殊的字符串进行编码。给定的字母表 A 由 26 个小写英文字母组成 A={a,b,…,z}。该字母表产生的升序字符串是指字符串中字母按照从左到右出现的次序与字母在字母表中出现的次序相同,且每个字符最多出现 1 次。例如,a,b,ab,bc,xyz 等字符串都是升序字符串。现在对字母表 A 产生的所有长度不超过 6 的升序字符串按照字典序排列并编码如下。
1 2 … 26 27 28 …
a b … z ab ac …
对于任意长度不超过 6 的升序字符串,迅速计算出它在上述字典中的编码。
编程任务:
对于给定的长度不超过 6 的升序字符串,编程计算出它在上述字典中的编码
输入
文件的第一行是一个正整数 k,表示接下来共有 k 行。
接下来的 k 行中,每行给出一个字符串。
输出
运行结束输出共有 k 行,每行对应于一个字符串的编码
样例输入
2
a
b
样例输出
1
2
分析:计算要分三步:
(1)计算所有小于k位字符串的总和
(2)计算所有等于k位但是首字母比输入小的字符串总和
(3)计算所有等于k位而且首字母相同但是字典序小的字符串总和(使用分治算法的思想去比较其子串使用(2)的方法)
代码如下
#include<stdio.h>
#include<string.h>
//f(i,k)表示以第i个字符打头的长度k的升序字符串个数位
int f(int i,int k){
int j;
int sum=0;
if(k==1){
return 1;
}else{
for(j=i+1;j<=26;j++){
sum+=f(j,k-1);
}
}
return sum;
}
int calculate(char a[]){
int i,j,count,n,length;
int sum=0;
int k=strlen(a);
//该for循环计算的是小于K位的字符串的总和
for(i=1;i<k;i++){
for(int j=1;j<=26;j++){
sum+=f(j,i);
}
}
int h=a[0]-'a'+1;
//该for循环计算的是等于K位的字符串但是首字母更小的总和
for(int i=1;i<h;i++){
sum+=f(i,k);
}
count = h;
//该for循环计算的是等于K位的字符串且首字母相同但是字典序更小的总和
for(i=1;i<k;i++){
n= a[i]-'a'+1;//计算当前字母
length=k-i;//计算当前字符串的长度
//计算子串中字典序更小的总和
for(j=count+1;j<n;j++){
sum+=f(j,length);
}
count=n;
}
return sum+1;
}
int main()
{
int n;
char a[300];
long long x;
while(scanf("%d",&n)!=EOF){ //使其可以通过oj的持续输入
getchar();
while(n--){
x=0;
gets(a);
x=calculate(a);
printf("%d\n",x);
}
}
return 0;
}