• 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
    ", 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

  • 相关阅读:
    扫描与爆破
    复习与PKI技术

    IIS与FTP
    IIS与WEB
    DNS部署与安全
    DHCP服务部署与安全
    文件共享服务CIFS
    NTFS权限
    关于操作运算符的一些小练习
  • 原文地址:https://www.cnblogs.com/yousiki/p/6556439.html
Copyright © 2020-2023  润新知