编码

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

原文地址:https://www.cnblogs.com/qswx/p/9308516.html