4032: [HEOI2015]最短不公共子串
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 446 Solved: 224
[Submit][Status][Discuss]
Description
在虐各种最长公共子串、子序列的题虐的不耐烦了之后,你决定反其道而行之。
Input
有两行,每行一个小写字母组成的字符串,分别代表A和B。
Output
输出4行,每行一个整数,表示以上4个问题的答案的长度。如果没有符合要求的答案,输出-1.
Sample Input
abcabc
Sample Output
4
2
4
HINT
对于100%的数据,A和B的长度都不超过2000
Source
本来以为是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 ", ans); 84 else 85 printf("%d ", -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 ", ans); 114 else 115 printf("%d ", -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 ", ans); 190 else 191 printf("%d ", -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 ", ans); 235 else 236 printf("%d ", -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