字典序问题

字典序问题


Time limit: 1000MS    Memory limit: 32768K
Total Submit: 574    Accepted: 193

在数据加密和数据压缩中常需要对特殊的字符串进行编码。给定的字母表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 的升序字符串,迅速计算出它在上述字典中的编码。

第一行是一个正整数k,表示接下来共有k行。
接下来的k行中,每行给出一个字符串。

输出共有k行,每行对应于一个字符串的编码。

Sample Input

2
a
b

Sample Output

1
2

代码
#include<stdio.h>
#include
<string.h>
constint N =26;
constint LEN=7;
char str[LEN];
int c[N+1][N+1]; //c[i][j]记录组合数

//使用杨辉三角计算n以内的c[i][j] c[i][j]=c[i-1][j-1]+c[i-1][j];
void Get_C(int n,int c[][N+1])
{
int i,left,right;
c[
0][0]=1;
for(i=1;i<=n;i++)
{
c[i][
0]=1;
c[i][i]
=1;
left
=1;right=i-1;
while(left<=right) //组合数性质:c[i][j]=c[i][i-j];
{
c[i][left]
= c[i-1][left-1]+c[i-1][left];
c[i][right
--]=c[i][left++];
}
}
}


//统计长度小于len的合法串
int Get_smaller(int len)
{
int i,curans=0;
for(i=1;i<len;i++)
curans
+=c[N][i];//统计长度为i的字符串种类
return curans;
}


//从左到右逐个统计相同前缀下的字符串个数
int Get_prefix(int len,char*str)
{
int i,j,curans=0;
int pre=-1; //记录前一字符
for(i=0;i<len;i++) //统计前缀为i-1位时,可出现的合法情形
{
int cur=str[i]-'a'; //当前字符
for(j=pre+1;j<cur;j++) //枚举摆放于当前前缀后的第一个字符,统计其合法串个数。
{
curans
+=c[N-j-1][len-i-1];
}
pre
=cur; //保留当前字符,作为情形的前一字符使用
}

return curans;

}


//判断输入是否非法
bool Is_legal(int len,char*str)
{
int i;
for(i=1;i<len;i++)
if(str[i]<=str[i-1])
{
returnfalse;
}
returntrue;
}



int main()
{
Get_C(N,c);
// 使用杨辉三角计算26以内的所有组合数c[i][j]
int tests;

while(scanf("%d",&tests)!=EOF)
{
while(tests--)
{
scanf(
"%s",str);
int len=strlen(str);
int ans;
bool flag=Is_legal(len,str);//判断输入串本身是否非法

if(flag==false)//输入字符串本身非法直接输出0
{
printf(
"0\n");
continue;
}

ans
=0;
ans
+=Get_smaller(len); //统计长度小于len的合法串

ans
+=Get_prefix(len,str); //从左到右逐个统计相同前缀下的字符串个数

ans
+=1; //加入其本身值
printf("%d\n",ans);
}
}
return0;

}


Source:算法设计与分析
原文地址:https://www.cnblogs.com/AndreMouche/p/1922843.html