zoukankan      html  css  js  c++  java
  • 【算法课】字典序问题

    题目描述

      在数据加密和数据压缩中常需要对特殊的字符串进行编码。给定的字母表A由26个小写字母组成。该字母表产生的升序字符串中字母从左到右出现的次序与字母在字母表中出现的次序相同,且每个字符最多出现1次。例如,a,b,ab,bc,xyz等字符串都是升序字符串。现在对字母表中产生的所有长度不超过6的升序字符串,计算它在字典中的编码。
     
     

    … 

    ab 

    ac 

     

    27 

    28 

    输入

    第一行一个整数T,表示测试组数(1<=T<=1e6)。
    接下来T行,每行一个长度不超过6的升序字符串(仅含小写字母)。 

    输出

    输出T行,每行一个整数代表答案。

    样例输入

    2
    a
    b

    样例输出

    1
    2

    【题意】

      其实这个题意是看这个列表看出来的,不重复的字母 按字典顺序给出,最大长度不超过6.

      和我们字典有点不同

      1、长度从小到大

      2、不存在重复的情况。

      

      多亏老师的提醒才能做出来,不然会在WA的路上越走越远。

      预处理所有f(i,j)  长度为i,以j字母开头的所有情况出来。

      

      预处理注意:1、不重复 ,2、长度占据一些位置,不能直接以下一个字母到z。

      

      求解答案时,注意如果当前是前一个字母的下一个位置不需要累加答案。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int N = 30;
     6  
     7 int Sum_Len[N];
     8 int Pre_Len[N];
     9 int f[8][N];
    10 char Str[N];
    11 
    12 // 预处理出所有f[i][j]
    13 // f[i][j] 长度为i,j开头的所有情况
    14 void Init(){
    15 
    16     //长度为1时所有情况就是 1 
    17     for(int i=0;i<27;i++)   f[1][i] = 1 ;
    18  
    19     //长度在递增时,转移方程为:f[len][i] += f[len-1][ i+1 ………z]
    20     //注意一点的是,因为长度的限制,所以无法枚举到最后一个字符。
    21     //f[len][i] += f[len-1][ i+1 ……… ('z' - len - 1) ]
    22     for( int Len = 2 ; Len <= 6 ; Len ++ ){
    23         for( int i=0 ; i < 26 ; i++ ){
    24             for( int j=i+1 ; j <= 26 - Len + 1 ; j++ ){
    25                 f[Len][i] += f[Len-1][j];
    26             }
    27         }
    28     }
    29 
    30     for(int i=1;i<=6;i++){
    31         for(int j=0;j<26;j++){
    32             Sum_Len[i] += f[i][j];
    33         }
    34         //记录在统计长度为i时所有情况。
    35         Pre_Len[i] = Pre_Len[i-1] + Sum_Len[i];
    36     }
    37  
    38 }
    39  
    40 int main()
    41 {
    42     Init();
    43     int T;
    44     scanf("%d",&T);
    45     while(T--){
    46         scanf("%s",Str+1);
    47         int len = strlen( Str+1 ) ;
    48         int Ans = Pre_Len[len-1] + 1 ;
    49         
    50         //预处理一个位置出来.
    51         Str[0] = 'a' - 1 ;
    52         for( int i = 1 , Len = len ; i <= len ; i++ ,Len-- ){
    53             //如果是连着的情况就不统计,例如abc
    54             
    55             if( Str[i-1] + 1 == Str[i]  ) continue ;
    56             
    57             //如果不是连着的需要把对应的位置进行累加,注意累加的起点.
    58             //如 ab(e) -> abc,abd 
    59             for( int j = Str[i-1] - 'a' + 1 ; j < Str[i]-'a' ; j++ ){
    60                 Ans += f[Len][j];
    61             }
    62         }
    63         printf("%d
    ",Ans);
    64     }
    65     return 0 ;
    66 }
    67  
    68  
    69  
    70 /*
    71  
    72 a
    73 1
    74  
    75 ab
    76 27
    77  
    78 yz
    79 351
    80  
    81 abc
    82 352
    83  
    84 bcd
    85 652
    86  
    87 */
    View Code

    【回溯的做法】

      就当练习dfs了,超时是正常的,因为搜索空间太大了。

     1 #pragma GCC optimize(2)
     2 #pragma GCC optimize(3)
     3 #include<unordered_map>
     4 #include<iostream>
     5 #include<cstdio>
     6 #include<map>
     7 using namespace std;
     8 unordered_map< string , int > Mp;
     9 int Len , No ;
    10 char character[27] ;
    11 
    12 inline void dfs( int pos , int len , string s ){
    13     if( (26 - pos) + len < Len ) return ;
    14     if( len == Len ){
    15         Mp[ s ] = ++No ;
    16         //cout << s << endl;
    17         return ;
    18     }
    19     //cout << " ##### "<< endl;
    20     if( pos == 26 ) return ;
    21     for( register int i = pos ; i < 26 ; i++ ){
    22         //cout << i << " ### " << endl;
    23         dfs( i + 1 , len + 1 , s+string(character+i,1) );
    24     }
    25 
    26 }
    27 int main()
    28 {
    29 
    30     for(int i=0;i<26;i++){
    31         character[i] = i+'a';
    32     }
    33 
    34     int T;
    35     for(Len = 1 ; Len <= 6 ; Len++ )
    36         dfs( 0 , 0 , "" );
    37 
    38     //cout << No << endl;
    39 
    40     //freopen("input.txt","r",stdin);
    41     //freopen("out2.txt","w",stdout);
    42     ios_base :: sync_with_stdio(false );
    43     cin.tie(NULL) , cout.tie(NULL);
    44     cin >> T;
    45     while(T--){
    46         string str ;
    47         cin >> str;
    48         cout << Mp[str] << endl;
    49     }
    50     return 0 ;
    51 }
    52 /*
    53 
    54 26 * 25 * 24 * 23 * 22 *21
    55 165765600
    56 
    57 */
    爆搜写法

    【对拍版】

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int N = 30;
     6 
     7 int Sum_Len[N];
     8 int Pre_Len[N];
     9 int f[8][N];
    10 char Str[N];
    11 
    12 // 预处理出所有f[i][j]
    13 // f[i][j] 长度为i,j开头的所有情况
    14 void Init(){
    15 
    16     //长度为1时所有情况就是 1
    17     for(int i=0;i<27;i++)   f[1][i] = 1 ;
    18 
    19     //长度在递增时,转移方程为:f[len][i] += f[len-1][ i+1 ………z]
    20     //注意一点的是,因为长度的限制,所以无法枚举到最后一个字符。
    21     //f[len][i] += f[len-1][ i+1 ……… ('z' - len - 1) ]
    22     for( int Len = 2 ; Len <= 6 ; Len ++ ){
    23         for( int i=0 ; i < 26 ; i++ ){
    24             for( int j=i+1 ; j <= 26 - Len + 1 ; j++ ){
    25                 f[Len][i] += f[Len-1][j];
    26             }
    27         }
    28     }
    29 
    30     for(int i=1;i<=6;i++){
    31         for(int j=0;j<26;j++){
    32             Sum_Len[i] += f[i][j];
    33         }
    34         //记录在统计长度为i时所有情况。
    35         Pre_Len[i] = Pre_Len[i-1] + Sum_Len[i];
    36     }
    37 
    38 }
    39 
    40 int main()
    41 {
    42     //freopen("input.txt","r",stdin);
    43     //freopen("out1.txt","w",stdout);
    44     Init();
    45     int T;
    46     scanf("%d",&T);
    47     while(T--){
    48         scanf("%s",Str+1);
    49         int len = strlen( Str+1 ) ;
    50         int Ans = Pre_Len[len-1] + 1 ;
    51 
    52         //预处理一个位置出来.
    53         Str[0] = 'a' - 1 ;
    54         for( int i = 1 , Len = len ; i <= len ; i++ ,Len-- ){
    55             //如果是连着的情况就不统计,例如abc
    56 
    57             if( Str[i-1] + 1 == Str[i]  ) continue ;
    58 
    59             //如果不是连着的需要把对应的位置进行累加,注意累加的起点.
    60             //如 ab(e) -> abc,abd
    61             for( int j = Str[i-1] - 'a' + 1 ; j < Str[i]-'a' ; j++ ){
    62                 Ans += f[Len][j];
    63             }
    64         }
    65         printf("%d
    ",Ans);
    66     }
    67     return 0 ;
    68 }
    69 
    70 
    71 
    72 /*
    73 
    74 a
    75 1
    76 
    77 ab
    78 27
    79 
    80 yz
    81 351
    82 
    83 abc
    84 352
    85 
    86 bcd
    87 652
    88 
    89 */
    正解
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int main()
     4 {
     5     freopen("input.txt","w",stdout);
     6     int T;
     7     T = 10 ;
     8     printf("%d
    ",T);
     9     for(int i=0;i<T;i++){
    10         int n = rand()%6+1;
    11         int a[30]={0};
    12         for(int i=0;i<26;i++){
    13             a[i] = i;
    14         }
    15         random_shuffle(a,a+26);
    16         sort(a,a+n);
    17         for(int i=0;i<n;i++){
    18             printf("%c",a[i]+'a');
    19         }
    20         puts("");
    21     }
    22 }
    造数据
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int main(){
     4 
     5     while(1){
     6         system("./造数据_字典序");
     7         system("./回溯版_字典序");
     8         system("./规律版_字典序");
     9         if(system("diff out1.txt out2.txt")) break;
    10     }
    11     return 0;
    12 }
    对拍函数
  • 相关阅读:
    Python--day62--什么时候用GET请求和POST请求
    Python--day62--ORM的使用
    使用 vs code 搭建vue项目(一)
    jquery如何模拟分页-小白进阶
    JavaScript 实现的4种数字千位符格式化方法
    web秀
    五十个UI设计资源网站
    基于 HTML5 WebGL 的 水泥工厂可视化系统
    ASP.NET MVC图片管理(上传,预览与显示)
    jQuery使用FormData上传文件
  • 原文地址:https://www.cnblogs.com/Osea/p/11437433.html
Copyright © 2011-2022 走看看