字典序问题

Description

在数据加密和数据压缩中常需要对特殊的字符串进行编码。给定的字母表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

Answer


#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;     

}