/*
和前面的几道题目很像,也是基于前后大小关系的字符串DP
状态为:F(l,s) 代表长度为l的起始为s的元素的个数。
按长度为阶段,转移方程为:F(l,s) = sum{ F(l-1,t) } ( s < t )
然后利用递推关系计算出所有长度为l的小于这个串的个数在加上长度小于l的串的个数即可。
╮(╯▽╰)╭,刚开始状态设成:长度为l的结束为e的元素的个数,不好推,纠结了好久。。。
*/
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <stdio.h>
2 #include <string.h>
3
4 int Count[ 6 ][ 27 ];
5 char Data[ 6 ];
6
7 void makelist( void )
8 {
9 int i,j,k;
10 memset( Count, 0, sizeof( Count ) );
11 for ( i = 1 ; i <= 26 ; ++ i )
12 Count[ 1 ][ i ] = 1;
13 for ( i = 2 ; i <= 5 ; ++ i ) {
14 for ( j = 1 ; j <= 26 ; ++ j )
15 for ( k = j+1 ; k <= 26 ; ++ k )
16 Count[ i ][ j ] += Count[ i-1 ][ k ];
17 }
18 }
19
20 int calc( int s, int v, int L )
21 {
22 int i,Sum = 0;
23 for ( i = s+1 ; i < v ; ++ i )
24 Sum += Count[ L ][ i ];
25 return Sum;
26 }
27
28 bool legal( int L )
29 {
30 for ( int i = 1 ; i < L ; ++ i )
31 if ( Data[ i ] <= Data[ i-1 ] )
32 return false;
33 return true;
34 }
35
36 int main()
37 {
38 makelist();
39 while ( ~scanf("%s",&Data[ 1 ]) ) {
40 int Len = strlen( &Data[ 1 ] );
41
42 if ( legal( Len ) ) {
43 int i,j,Sum = 1;
44
45 Data[ 0 ] = 'a'-2;//补充循环边界
46 //按位向后求解
47 for ( i = 1 ; i <= Len ; ++ i )
48 Sum += calc( Data[ i-1 ]-'a'+1, Data[ i ]-'a'+1, Len-i+1 );
49
50 //计算长度小于l的合法串的个数
51 for ( i = 1 ; i < Len ; ++ i )
52 for ( j = 1 ; j <= 26 ; ++ j )
53 Sum += Count[ i ][ j ];
54
55 printf("%d\n",Sum);
56 }else printf("0\n");
57 }
58 return 0;
59 }