zoukankan      html  css  js  c++  java
  • 编码

    Problem description

    编码工作常被运用于密文或压缩传输。这里我们用一种最简单的编码方式进行编码:把一些有规律的单词编成数宇。
    字母表中共有26个字母{a,b,…,z},这些特殊的单词长度不超过6且字母按升序排列。把所有这样的单词放在一起,按字典顺序排列,一个单词的编码就对应着它在字典中的位置。
      例如:
      a→1
      b→2
      ……
      z→26
      ab→27
      ac→28
      ……
    你的任务就是对于所给的单词,求出它的编码。

    Input format 

    仅一行,被编码的单词。

    Output format

    仅一行,对应的编码。如果单词不在字母表中,输出0。

    Algorithm design

    模拟AC/动态规划AC

    Problem analysis

    模拟AC

    先敲一下暴力,方便对拍

    模拟的思路很好想,将字母转化为数字,进行类似26进制的依次加法

    (发现好像直接用字母处理更方便..)

    但26进制应该z过了之后是aa这样,所以还是有所不同

    无论如何,到底只是一个简单的维护单调序列的问题

    每次从后往前枚举,找到第1个可以进的数字,加1

    同时将其后所有数字变为从它开始的单调递增1序列

    (如果是26进制则应该将之后所有数字变为a)

    当然在找数字的时候也要注意保证修改后不会有数超过z

    如果找不到这样的数字,那么加1位,从头开始abc…

    每次将得到的结果与目标进行比对即可

    至于不在字母表中,直接在开头判断,出现非单调性,或者不在a~z就输0

    复杂度不高,O(26个数中长度不大于6的有序区间的个数*6),不会算…

    可以过,但是数据模拟到6位的时候,程序会爆掉,不知道为什么

    动态规划AC

    在随手画画的过程中发现

    以字母j开头的长为i的字母的总数是一个可以算出的值

    比如说,3,w就是3,x+2,x,其他的以此类推

    Opt[i][j]=opt[i][j+1]+opt[i-1][j+1]

    为什么呢

    在同一长度下,i总是包括i+1的所有情况(只是开头字母换了)

    又因为i比i+1少1,所以第二个字母又比i+1的第二个字母多1种情况

    故在第二个字母为i+1时,opt[i][j]又有一个opt[i-1][j+1]

    那么所有的opt[i][j]都是能算出来的

    接着就是数学处理了

    为了方便,先将小于所给单词的所有情况都加上

    然后每次取出位数相同,首数却小于自身的情况,再删去自己的首数继续

    这里有个难点,每次开始枚举的起点,都应该是上一次的首数+1

    其他没什么了

    Source code

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 struct node
     6 {
     7     int num[7];
     8     int len;
     9 }ans,key;//定义结构体,存储数字和规格
    10 string st;
    11 
    12 void input()
    13 {
    14     freopen("test.in","r",stdin);
    15     freopen("test.out","w",stdout);
    16     cin>>st;
    17     memset(key.num,0,sizeof(key.num));
    18     memset(ans.num,0,sizeof(ans.num));
    19     key.len=1;
    20     key.num[1]=1;
    21     ans.len=st.size();
    22     for(int i=1;i<=ans.len;i++)
    23         ans.num[i]=st[i-1]-'a'+1;
    24 //将答案保存入结构体
    25     return ;
    26 }
    27 
    28 void operate(node now,int turn)
    29 {
    30     if(now.len==ans.len)
    31     {
    32         bool flag=true;
    33         for(int i=1;i<=now.len;i++)
    34             if(now.num[i]!=ans.num[i])
    35             {
    36                 flag=false;
    37                 break;
    38             }
    39         if(flag)
    40         {
    41             cout<<turn<<endl;
    42             return;
    43         }
    44     }//满足答案即输出
    45     for(int i=now.len;i>=1;i--)
    46         if(now.num[i]+now.len-i<26)
    47         {
    48             now.num[i]++;
    49             for(int j=i+1;j<=now.len;j++)
    50                 now.num[j]=now.num[j-1]+1;
    51             operate(now,turn+1);
    52             return ;
    53         }
    54     now.len++;
    55     for(int i=1;i<=now.len;i++)
    56         now.num[i]=i;
    57     operate(now,turn+1);
    58 //和Analysis说的一样了
    59     return ;
    60 }
    61 
    62 int main()
    63 {
    64     input();
    65     for(int i=1;i<=ans.len;i++)
    66         if((i>1&&ans.num[i]<=ans.num[i-1])||ans.num[i]>26||ans.num[i]<1)
    67         {
    68             cout<<"0"<<endl;
    69             return 0;
    70         }
    71 //直接判断是否不符合
    72     operate(key,1);
    73     return 0;
    74 }
    模拟
     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 int cnt[10][30],ans,len;
     6 //cnt[i][j]表以i开头的j位数有多少个
     7 string st;
     8 
     9 void input()
    10 {
    11     freopen("test.in","r",stdin);
    12     freopen("test.out","w",stdout);
    13     cin>>st;
    14     len=st.size();
    15     return ;
    16 }
    17 
    18 void pretreatment()
    19 {
    20     memset(cnt,0,sizeof(cnt));
    21     for(int i=1;i<=26;i++)
    22         cnt[1][i]=1;
    23     //1位的任何字母都只有一种
    24     for(int i=2;i<=6;i++)
    25         for(int j=26-i+1;j>=1;j--)
    26             cnt[i][j]=cnt[i][j+1]+cnt[i-1][j+1];
    27     //从当前位数下可以采用的最大数首开始递减,如:w,3比x,3多了x,2种情况
    28     return ;
    29 }
    30 
    31 void operate()
    32 {
    33     ans=1;
    34     for(int i=1;i<len;i++)
    35         for(int j=1;j<=26-i+1;j++)
    36             ans+=cnt[i][j];
    37     //先把比自己位数小的算上,可以用前缀和优化,但是可以过就不费事了
    38     int wei=1;
    39     while(len)
    40     {
    41         for(int i=wei;i<st[0]-'a'+1;i++)
    42             ans+=cnt[len][i];
    43         //把同位数中低于自己的算上
    44         wei=st[0]-'a'+2;
    45         st=st.substr(1);
    46         len--;
    47     }
    48     return ;
    49 }
    50 
    51 int main()
    52 {
    53     input();
    54     for(int i=0;i<len;i++)
    55         if((i>0&&st[i]<=st[i-1])||st[i]>'z'||st[i]<'a')
    56         {
    57             cout<<"0"<<endl;
    58             return 0;
    59         }
    60     //先判断是不是符合单词
    61     pretreatment();
    62     operate();
    63     cout<<ans<<endl;
    64     return 0;
    65 }
    动规

    over

  • 相关阅读:
    js 经纬度计算直线距离
    lua 把图片转换成base64
    js 选中div中的文本
    .net EasyTree显示所级层级(无限级、整层级颗树)的另类写法。非递归
    c# windows服务 一个项目安装多个服务
    MD5 .net与PHP加密值一样的加密代码
    mvc 目录不存在/Directory does not exist.的解决方案
    .net webapi项目中支持session
    .net 中HttpClient 携带cookie传输
    iis虚拟目录或应用程序不继承父站点的web.config配置信息
  • 原文地址:https://www.cnblogs.com/qswx/p/9308516.html
Copyright © 2011-2022 走看看