题目链接:http://poj.org/problem?id=1850
题目大意:
按照字典序对升序排列组成的字母进行编号,给出一个长度不超过10的串,求出它的编号是多少?如果无法进行编号则输出0。
题目分析:
先判断字符串是不是升序的,如果不是升序的则不存在编号,直接输出0即可。
满足升序要求的,则先根据长度len,把长度小于len的串整个处理一下,再对长度为len的递归求解。
1.定义长度为i,以字母c开头的串的个数为f[i][c]。很容易看出来:f[i][c]=Σf[i-1][k](k=c+1-->'z'-i+2),解释一下k的取值,因为要求升序,所以以字母c开头的长度为i的串,相当于在长度为i-1的串前面插入一个c,可以插的串必然从c+1开始,直到‘z'-i+2。这个上界是为了满足长度的要求,长度为i-1的串最多只能以‘z'-i+2开头。
2.在定义f[i][c]的时候,已经看出之中的递推关系了。那么对于长度为len的,按照串的顺序,依次处理如下:
for(int i='a';i<s[0];i++)//对首字母特殊处理 ans+=f[len][i]; for(int i=1;i<len;i++) for(int j=s[i-1]+1;j<s[i];j++)//对第i个字母处理。要注意是<s[i]。 ans+=f[len-i][j]; ans++;//串本身的那个1.
这样就求出解了。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 using namespace std; 6 int f[15]['z'+5]; 7 int main() 8 { 9 string s; 10 memset(f,0,sizeof(f)); 11 for(int i='a';i<='z';i++) 12 f[1][i]=1; 13 for(int i=2;i<=10;i++) 14 for(int c='a';c<='z'-i+1;c++) 15 for(int k=c+1;k<='z'-i+2;k++) 16 f[i][c]+=f[i-1][k]; 17 while (cin>>s) 18 { 19 int len=s.size(); 20 int ans=0; 21 bool ok=0; 22 for(int i=1;i<len;i++) 23 if(s[i]<=s[i-1]) 24 { 25 cout<<0<<endl; 26 ok=1; 27 break; 28 } 29 if(ok) continue; 30 for(int i=1;i<len;i++) 31 for(int c='a';c<='z'-i+1;c++) 32 ans+=f[i][c]; 33 for(int i='a';i<s[0];i++) 34 ans+=f[len][i]; 35 for(int i=1;i<len;i++) 36 for(int j=s[i-1]+1;j<s[i];j++) 37 ans+=f[len-i][j]; 38 ans++; 39 cout<<ans<<endl; 40 } 41 return 0; 42 }