BZOJ 4032: [HEOI2015]最短不公共子串

4032: [HEOI2015]最短不公共子串

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 446  Solved: 224
[Submit][Status][Discuss]

Description

 在虐各种最长公共子串、子序列的题虐的不耐烦了之后,你决定反其道而行之。

一个串的“子串”指的是它的连续的一段,例如bcd是abcdef的子串,但bde不是。
一个串的“子序列”指的是它的可以不连续的一段,例如bde是abcdef的子串,但bdd不是。
下面,给两个小写字母串A,B,请你计算:
(1) A的一个最短的子串,它不是B的子串
(2) A的一个最短的子串,它不是B的子序列
(3) A的一个最短的子序列,它不是B的子串
(4) A的一个最短的子序列,它不是B的子序列

Input

有两行,每行一个小写字母组成的字符串,分别代表A和B。

Output

输出4行,每行一个整数,表示以上4个问题的答案的长度。如果没有符合要求的答案,输出-1.

Sample Input

aabbcc
abcabc

Sample Output

2
4
2
4

HINT

 

 对于100%的数据,A和B的长度都不超过2000


 

 

Source

 
[ Submit][ Status][ Discuss]

 

本来以为是HEOI2015的大水题,然后被小甜甜安利了一发序列自动机……

我等蒟蒻并不会此等算法,所以只好暴力喽!

 

拿到之后看到是四个答案,就分别考虑。

 

问题一 A的一个最短的子串,不是B的子串

这个比较简单哈,刺姐姐和任哥哥不约而同地给出了HASH做法——预先对B串的每个子串处理出HASH值,扔进哈希表里,然后暴力枚举A串的每个子串,查询是否在B中出现过,如果没有出现过,就可以用来更新答案。

然后蒟蒻的我表示并不会HASH此等算法,只好KMP暴力喽。每次枚举A串中的一个位置,作为其子串的左端点,记为$L$。此时我们希望查询所有以$L$作为左端点的A的子串,最短的一个不是B的子串的东东。这个就对A串的$[L,Len]$求next数组,拿B串跑一遍KMP就行了。时间复杂度$O(N^2)$。

 

问题二 A的一个最短的子串,不是B的子序列

这个非常简单哈,众神犇(除了我的所有人)一致给出了暴力做法。枚举A的子串的左端点,然后暴力检查至少以那个点作为右端点,该子串才不是B的子序列。时间复杂度$O(N^2)$。

 

问题三 A的一个最短的子序列,不是B的子串

这个也很简单哈,众神犇表示不直接序列自动机直接上就可以,但是蒟蒻的我依旧不会,只好写暴力了哈。

先取出B的所有子串,塞到Trie树里面去,总的节点数是$O(N^2)$,算了下内存有点吃紧,就用map<int,int>了。

然后在每个节点上记录一个标记mark,代表A串中最少选出几个字符,才能匹配到Trie上的这个节点来。这个直接DFS就可以得到了。

然后在在每个Trie树节点上枚举一个字符,如果该节点没有这个字符的出边,那么A串就有机会找出一个合法的解了。此时我们只需要知道A串在mark位置之后是否出现过字符c即可,这个很简单喽。

 

问题四 A的一个最短的子序列,不是B的子序列

这个最最简单哈,只要用$f_{i,j}$表示使用A的前$i$个字符,使得B不得不使用前$j$个字符和其匹配,所能使用的最少字符数。这个$O(N^2)$动态规划,太简单就不说了。

 

然后顺利用四种暴力水过HEOI2015的最水一题。

 

  1 #include <map>
  2 #include <cstdio>
  3 #include <cstring>
  4 
  5 #define chr char
  6 #define rst register
  7 #define rnt register int
  8 
  9 template <class T>
 10 inline T min(const T &a, const T &b)
 11 {
 12     return a < b ? a : b;
 13 }
 14 
 15 template <class T>
 16 inline T max(const T &a, const T &b)
 17 {
 18     return a > b ? a : b;
 19 }
 20 
 21 #define mxn 2005
 22 #define mxm 4000005
 23 
 24 int n, m;
 25 
 26 chr a[mxn];
 27 chr b[mxn];
 28 
 29 namespace case1
 30 {
 31     int tot;
 32     int pos;
 33     int vis[mxn];
 34     int fil[mxn];
 35     int nxt[mxn][26];
 36     
 37     inline int solve(int s)
 38     {
 39         tot = 1;
 40         pos = 1;
 41         
 42         memset(vis, 0, sizeof vis);
 43         memset(nxt, 0, sizeof nxt);
 44         memset(fil, 0, sizeof fil);
 45         
 46         for (rnt i = s; i < n; ++i)
 47             pos = nxt[pos][a[i] - 'a'] = ++tot;
 48         
 49         fil[1] = 1;
 50         
 51         for (rnt i = 0; i < 26; ++i)
 52             if (nxt[1][i])
 53                 fil[nxt[1][i]] = 1;
 54             else
 55                 nxt[1][i] = 1;
 56         
 57         for (rnt i = 2; i <= tot; ++i)
 58             for (rnt j = 0; j < 26; ++j)
 59                 if (nxt[i][j])
 60                     fil[nxt[i][j]] = nxt[fil[i]][j];
 61                 else
 62                     nxt[i][j] = nxt[fil[i]][j];
 63         
 64         pos = 1;
 65         
 66         for (rnt i = 0; i < m; ++i)
 67             vis[pos = nxt[pos][b[i] - 'a']] = 1;
 68         
 69         for (rnt i = 2; i <= tot; ++i)
 70             if (!vis[i])return i - 1;
 71         
 72         return 1E9;
 73     }
 74     
 75     inline void main(void)
 76     {
 77         int ans = 1E9;
 78 
 79         for (rnt i = 0; i < n; ++i)
 80             ans = min(ans, solve(i));
 81         
 82         if (ans != 1E9)
 83             printf("%d\n", ans);
 84         else
 85             printf("%d\n", -1);
 86     }
 87 }
 88 
 89 namespace case2
 90 {
 91     inline int solve(int s)
 92     {
 93         for (rnt i = s, j = 0; i < n; ++i, ++j)
 94         {
 95             while (j < m && b[j] != a[i])
 96                 ++j;
 97             
 98             if (j >= m)
 99                 return i - s + 1;
100         }
101         
102         return 1E9;
103     }
104     
105     inline void main(void)
106     {
107         int ans = 1E9;
108         
109         for (rnt i = 0; i < n; ++i)
110             ans = min(ans, solve(i));
111         
112         if (ans != 1E9)
113             printf("%d\n", ans);
114         else
115             printf("%d\n", -1);
116     }
117 }
118 
119 namespace case3
120 {
121     int nxt[mxn][26];
122     
123     inline void prework(void)
124     {
125         for (rnt i = 0; i <= n; ++i)
126             for (rnt j = 0; j < 26; ++j)
127                 nxt[i][j] = n;
128         
129         for (rnt i = 0; i < n; ++i)
130             nxt[i][a[i] - 'a'] = i;
131         
132         for (rnt i = n - 2; i >= 0; --i)
133             for (rnt j = 0; j < 26; ++j)
134                 nxt[i][j] = min(nxt[i][j], nxt[i + 1][j]);
135     }
136     
137     typedef std::map<int, int> map;
138     typedef std::map<int, int>::iterator itr;
139     
140     int tot = 1;
141     int mrk[mxm];
142     map son[mxm];
143     
144     inline void build(void)
145     {
146         for (rnt i = 0; i < m; ++i)
147         {
148             rnt t = 1;
149             
150             for (rnt j = i; j < m; ++j)
151             {
152                 rnt c = b[j] - 'a';
153                 
154                 if (son[t][c] == 0)
155                     son[t][c] = ++tot;
156                 
157                 t = son[t][c];
158             }
159         }
160     }
161     
162     int ans = 1E9;
163     
164     inline void getmark(int t = 1, int d = 1)
165     {
166         if (d >= ans)return;
167 
168         int p = mrk[t];
169         
170         for (rnt i = 0; i < 26; ++i)
171             if (nxt[p][i] < n) {
172                 if (son[t][i])
173                     mrk[son[t][i]] = nxt[p][i] + 1,
174                     getmark(son[t][i], d + 1);
175                 else
176                     ans = min(ans, d);
177             }
178     }
179     
180     inline void main(void)
181     {
182         build();
183         
184         prework();
185         
186         getmark();
187         
188         if (ans != 1E9)
189             printf("%d\n", ans);
190         else
191             printf("%d\n", -1);
192     }
193 }
194 
195 namespace case4
196 {
197     int nxt[mxn][26];
198     
199     int len[mxn][mxn];
200     
201     inline void main(void)
202     {
203         for (rnt i = 0; i <= m; ++i)
204             for (rnt j = 0; j < 26; ++j)
205                 nxt[i][j] = m;
206         
207         for (rnt i = 0; i < m; ++i)
208             nxt[i][b[i] - 'a'] = i;
209         
210         for (rnt i = m - 2; i >= 0; --i)
211             for (rnt j = 0; j < 26; ++j)
212                 nxt[i][j] = min(nxt[i][j], nxt[i + 1][j]);
213         
214         memset(len, 0x3f, sizeof len);
215         
216         len[0][0] = 0;
217         
218         rnt t;
219         
220         for (rnt i = 0; i < n; ++i)
221             for (rnt j = 0; j <= m; ++j)
222                 if (len[i][j] < 0x3f3f3f3f) {
223                     t = nxt[j][a[i] - 'a'] + 1;
224                     len[i + 1][j] = min(len[i + 1][j], len[i][j]);
225                     len[i + 1][t] = min(len[i + 1][t], len[i][j] + 1);
226                 }
227         
228         int ans = 1E9;
229         
230         for (rnt i = 0; i <= n; ++i)
231             ans = min(ans, len[i][m + 1]);
232         
233         if (ans != 1E9)
234             printf("%d\n", ans);
235         else
236             printf("%d\n", -1);
237     }
238 }
239 
240 signed main(void)
241 {
242 #ifndef ONLINE_JUDGE
243     freopen("in", "r", stdin);
244     freopen("out", "w", stdout);
245 #endif    
246     
247     scanf("%s", a); n = strlen(a);
248     scanf("%s", b); m = strlen(b);
249     
250     case1::main();
251     case2::main();
252     case3::main();
253     case4::main();
254 }

 

@Author: YouSiki

 

转载于:https://www.cnblogs.com/yousiki/p/6556439.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值