首页 > 技术文章 > J - Clairewd’s message HDU - 4300(扩展kmp)

letlifestop 2018-12-22 12:03 原文

题目链接:https://cn.vjudge.net/contest/276379#problem/J

感觉讲的很好的一篇博客:https://subetter.com/articles/extended-kmp-algorithm.html

题目大意:这是一个编译密码的题目,首先给你26个字母分别重新编码后的对应的字母,然后再给你一个字符串,字符串的前一部分是编译过后的,后一部分是编译之前的,但是后一部分可能会有损失,问你用尽量少的字符,将整个字符串补起来,也就是前面是暗文,后面是明文。

具体思路:扩展kmp的裸题, 我们可以另外开一个字符,这个字符存储的是编译过后的,我们现在把初始密码串比喻成s1,编译过后的密码串比喻成s2,这个样的话,我们直接找出s2中的后缀中,满足是s1的前缀的最长的找出来,这个就是残缺的暗文,前面的就是明文了。

 对于扩展kmp的理解:首先说一下我理解的扩展kmp的作用,我们假设当前有一个字符串t,长度是len。t[i]代表的是以字符串的第i位开始,以t[len-1]为截止位置的t的子串,然后nex[i]的作用就是求t[i]和t的最大前缀和的匹配数。

其实extend的作用和nex的具体实现内容是一样的,因为在求nex的时候,我们当前是以t为模板串,t[i]是子串。在求extend的时候,我们是以t为模板串,s是对比串的。

AC代码:

 1 #include<iostream>
 2 #include<stack>
 3 #include<iomanip>
 4 #include<stdio.h>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<string>
 8 #include<map>
 9 #include<cstring>
10 #include<vector>
11 using namespace std;
12 # define ll long long
13 const int maxn = 1e6+10;
14 char str[maxn],com[maxn];
15 char tmp[maxn];
16 int nex[maxn],extend[maxn];
17 map<char,char>vis;
18 void getnex(int len)
19 {
20     int a=0,p=0;
21     nex[0]=len;//第0位是自己
22     for(int i=1; i<len; i++)
23     {
24         if(i>=p||i+nex[i-a]>=p)
25         {
26             if(i>=p)
27                 p=i;
28             while(p<len&&tmp[p]==tmp[p-i])
29                 p++;
30             nex[i]=p-i;
31             a=i;
32         }
33         else
34             nex[i]=nex[i-a];
35     }
36 }
37 void exkmp(int len1,int len2)
38 {
39     getnex(len2);
40     int a=0,p=0;
41     for(int i=0; i<len1; i++)
42     {
43         if(i>=p||i+nex[i-a]>=p)
44         {
45             if(i>=p)
46                 p=i;
47             while(p<len1&&p-i<len2&&str[p]==tmp[p-i])
48                 p++;
49             extend[i]=p-i;
50             a=i;
51         }
52         else
53             extend[i]=nex[i-a];
54     }
55 }
56 int main()
57 {
58     int T;
59     scanf("%d",&T);
60     while(T--)
61     {
62         scanf("%s",com);
63         scanf("%s",str);
64         for(int i=0; i<26; i++)
65         {
66             vis[com[i]]='a'+i;
67         }
68         int len=strlen(str);
69         for(int i=0; i<len; i++)
70         {
71             tmp[i]=vis[str[i]];
72         }
73         exkmp(len,len);
74         int i;
75         for( i=0;i<len;i++){
76         if(i+extend[i]>=len&&i>=extend[i])break;//求满足情况的前缀
77         }
78         for(int j=0;j<i;j++){
79                 printf("%c",str[j]);
80         }
81         for(int j=0;j<i;j++){
82                 printf("%c",vis[str[j]]);
83         }
84         printf("\n");
85     }
86     return 0;
87 }

 

推荐阅读