Transmitting and memorizing information is a task that requires different coding systems for the best use of the available space. A well known system is that one where a number is associated to a character sequence. It is considered that the words are made only of small characters of the English alphabet a,b,c, ..., z (26 characters). From all these words we consider only those whose letters are in lexigraphical order (each character is smaller than the next character).
The coding system works like this:
• The words are arranged in the increasing order of their length.
• The words with the same length are arranged in lexicographical order (the order from the dictionary).
• We codify these words by their numbering, starting with a, as follows:
a - 1
b - 2
...
z - 26
ab - 27
...
az - 51
bc - 52
...
vwxyz - 83681
...
Specify for a given word if it can be codified according to this coding system. For the affirmative case specify its code.
The coding system works like this:
• The words are arranged in the increasing order of their length.
• The words with the same length are arranged in lexicographical order (the order from the dictionary).
• We codify these words by their numbering, starting with a, as follows:
a - 1
b - 2
...
z - 26
ab - 27
...
az - 51
bc - 52
...
vwxyz - 83681
...
Specify for a given word if it can be codified according to this coding system. For the affirmative case specify its code.
The only line contains a word. There are some constraints:
• The word is maximum 10 letters length
• The English alphabet has 26 characters.
• The word is maximum 10 letters length
• The English alphabet has 26 characters.
The output will contain the code of the given word, or 0 if the word can not be codified.
bf
55
思路:主要想清楚,只要选出一定的字母,那么他们的顺序就一定确定下来了,接下来就是找排列数的问题了,具体解释看代码
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int c[27][27] = {0};//储存组合数 //打表,利用杨辉三角计算每一个组合数 void play_table(){ int i,j; for(i = 0; i <= 26; i++){ for(j = 0; j <= i; j++){ if(j == 0 || j == i) c[i][j] = 1; else c[i][j] = c[i-1][j-1] + c[i-1][j]; } } c[0][0] = 0; return ; } int main(){ play_table();//打表 int i,j; char str[13]; scanf("%s",str); int len = strlen(str);//字符串长度 for(i = 1; i < len; i++){//检查字符串是否符合要求 if(str[i-1] >= str[i]){ printf("0\n"); return 0; } } //先求出,除掉最后一位字母的全部升序排列种类,因为除去最后一位字母,前面任意长度的种类都是在这个长度下的全部种类数 //因为只有种类满了,才会有下一位字母嘛 int sum = 0; for(i = 1; i < len; i++){ sum += c[26][i]; //这句话做何理解:因为要求是升序的,因此一旦为选出了几个字母,那么这几个字母的顺序就确定了,所有 //我们要做的仅仅只是在26个字母中选出我需要的字母个数,即可所以直接c[26][i] } //下面要进行最后对总长度序列的种类计算,因为总长度序列的种类数一般不会是这个长度下总的全部种类数,所以要从头一个一个计算 //那么思路是什么呢? //先从第一个字母看假设是序列是ebcdf,第一个是e,那么肯定要计算比e小的字母为开头的排列种类数,那么比e小的话有a,b,c,d //那么是不是就可以分别让这四个字母开头(这个字母就确定下来了),然后算它之后剩下的那一串字母的排列数,那剩下的这串的排列数怎么算? //首先增序,所有我们可以选的字母肯定要大于已经确定的这个开头的字母了对吧,那么为们可以选择的字母数就是26-‘开头字母’,选多少个呢, //那肯定是选剩下字符串的长度个啦,因为题目要求递增,所以一旦你选出来了,那么顺序一定是确定了,不需要担心我选出来的不是递增的 for(i = 0; i < len; i++){ char ch; if(i == 0) ch = 'a'; //如果是第一个,他的前面没有字母那么就从a开始看好了 else ch = str[i-1]+1; //否则,从那里开始看呢?肯定是当前位置的前一个字符的下一个开始看了,因为至少要比前一个大1嘛,这句话可能不好理解,举个栗子 //a e k m z 这个字符串,假设当前为看到k这个字母,前一个是e,k这个位置还有谁可以开头呢,首先肯定大于e //所有要从‘e’+1为开头算起,也就是f,所以才有了str[i-1]+1,懂了吧 while(ch <= str[i]-1){ //还是刚才的栗子,枚举开头是不是肯定要枚举到比k小的那个字母也就是j,你可能问为什么不能把k算上,因为以k为开头的 //排列数不一定是所有的排列数可能排到中间字符串就停了,而他之前的一定是所有的可以用组合数直接相加,所以以k开头的要放到下一轮中判断 sum += c['z'-ch][len-i-1]; //这里的道理前面已经解释了,注意这里要写成z-ch,字符之间运算,否则结果会错误 ch++; } } printf("%d\n",sum+1); //正如之前说的,每次找到都是他之前的种类数,所以最后加上他本身 return 0; }