zoukankan      html  css  js  c++  java
  • Match & Catch CodeForces

    题意:

    给出两个字符串a,b,求一个字符串,这个字符串是a和b的子串,

    且只在a,b中出现一次,要求输出这个字符串的最小长度。

    题解:

    将a串放入后缀自动机中,然后记录一下每个节点对应的子串出现的次数

    然后把b串取自动机中匹配

    然后判断一下

      1 #include <set>
      2 #include <map>
      3 #include <stack>
      4 #include <queue>
      5 #include <cmath>
      6 #include <ctime>
      7 #include <cstdio>
      8 #include <string>
      9 #include <vector>
     10 #include <cstring>
     11 #include <iostream>
     12 #include <algorithm>
     13 #include <unordered_map>
     14 
     15 #define  pi    acos(-1.0)
     16 #define  eps   1e-9
     17 #define  fi    first
     18 #define  se    second
     19 #define  rtl   rt<<1
     20 #define  rtr   rt<<1|1
     21 #define  bug                printf("******
    ")
     22 #define  mem(a, b)          memset(a,b,sizeof(a))
     23 #define  name2str(x)        #x
     24 #define  fuck(x)            cout<<#x" = "<<x<<endl
     25 #define  sfi(a)             scanf("%d", &a)
     26 #define  sffi(a, b)         scanf("%d %d", &a, &b)
     27 #define  sfffi(a, b, c)     scanf("%d %d %d", &a, &b, &c)
     28 #define  sffffi(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d)
     29 #define  sfL(a)             scanf("%lld", &a)
     30 #define  sffL(a, b)         scanf("%lld %lld", &a, &b)
     31 #define  sfffL(a, b, c)     scanf("%lld %lld %lld", &a, &b, &c)
     32 #define  sffffL(a, b, c, d) scanf("%lld %lld %lld %lld", &a, &b, &c, &d)
     33 #define  sfs(a)             scanf("%s", a)
     34 #define  sffs(a, b)         scanf("%s %s", a, b)
     35 #define  sfffs(a, b, c)     scanf("%s %s %s", a, b, c)
     36 #define  sffffs(a, b, c, d) scanf("%s %s %s %s", a, b,c, d)
     37 #define  FIN                freopen("../in.txt","r",stdin)
     38 #define  gcd(a, b)          __gcd(a,b)
     39 #define  lowbit(x)          x&-x
     40 #define  IO                 iOS::sync_with_stdio(false)
     41 
     42 
     43 using namespace std;
     44 typedef long long LL;
     45 typedef unsigned long long ULL;
     46 const ULL seed = 13331;
     47 const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
     48 const int maxm = 8e6 + 10;
     49 const int INF = 0x3f3f3f3f;
     50 const int mod = 1e9 + 7;
     51 const int maxn = 250007;
     52 char s[maxn];
     53 int Q;
     54 
     55 struct Suffix_Automaton {
     56     int last, tot, nxt[maxn << 1][26], fail[maxn << 1];//last是未加入此字符前最长的前缀(整个串)所属的节点的编号
     57     int len[maxn << 1];// 最长子串的长度 (该节点子串数量 = len[x] - len[fa[x]])
     58     int sa[maxn << 1], c[maxn << 1];
     59     int sz[maxn << 1];// 被后缀链接的个数,方便求节点字符串的个数
     60     LL num[maxn << 1];// 该状态子串的数量
     61     LL maxx[maxn << 1];// 长度为x的子串出现次数最多的子串的数目
     62     LL sum[maxn << 1];// 该节点后面所形成的自字符串的总数
     63     LL subnum, sublen;// subnum表示不同字符串数目,sublen表示不同字符串总长度
     64     int X[maxn << 1], Y[maxn << 1]; // Y表示排名为x的节点,X表示该长度前面还有多少个
     65     int minn[maxn << 1], mx[maxn << 1];//minn[i]表示多个串在后缀自动机i节点最长公共子串,mx[i]表示单个串的最长公共子串
     66     void init() {
     67         tot = last = 1;
     68         fail[1] = len[1] = 0;
     69         for (int i = 0; i < 26; i++) nxt[1][i] = 0;
     70     }
     71 
     72     void extend(int c) {
     73         int u = ++tot, v = last;
     74         len[u] = len[v] + 1;
     75         num[u] = 1;
     76         for (; v && !nxt[v][c]; v = fail[v]) nxt[v][c] = u;
     77         if (!v) fail[u] = 1, sz[1]++;
     78         else if (len[nxt[v][c]] == len[v] + 1) fail[u] = nxt[v][c], sz[nxt[v][c]]++;
     79         else {
     80             int now = ++tot, cur = nxt[v][c];
     81             len[now] = len[v] + 1;
     82             memcpy(nxt[now], nxt[cur], sizeof(nxt[cur]));
     83             fail[now] = fail[cur];
     84             fail[cur] = fail[u] = now;
     85             for (; v && nxt[v][c] == cur; v = fail[v]) nxt[v][c] = now;
     86             sz[now] += 2;
     87         }
     88         last = u;
     89         //return len[last] - len[fail[last]];//多添加一个子串所产生不同子串的个数
     90     }
     91 
     92     void get_num() {// 每个节点子串出现的次数
     93         for (int i = 1; i <= tot; i++) X[len[i]]++;
     94         for (int i = 1; i <= tot; i++) X[i] += X[i - 1];
     95         for (int i = 1; i <= tot; i++) Y[X[len[i]]--] = i;
     96         for (int i = tot; i >= 1; i--) num[fail[Y[i]]] += num[Y[i]];
     97     }
     98 
     99     void get_maxx(int n) {// 长度为x的子串出现次数最多的子串的数目
    100         get_num();
    101         for (int i = 1; i <= tot; i++) maxx[len[i]] = max(maxx[len[i]], num[i]);
    102     }
    103 
    104     void get_sum() {// 该节点后面所形成的自字符串的总数
    105         get_num();
    106         for (int i = tot; i >= 1; i--) {
    107             sum[Y[i]] = 1;
    108             for (int j = 0; j <= 25; j++)
    109                 sum[Y[i]] += sum[nxt[Y[i]][j]];
    110         }
    111     }
    112 
    113     void get_subnum() {//本质不同的子串的个数
    114         subnum = 0;
    115         for (int i = 1; i <= tot; i++) subnum += len[i] - len[fail[i]];
    116     }
    117 
    118     void get_sublen() {//本质不同的子串的总长度
    119         sublen = 0;
    120         for (int i = 1; i <= tot; i++) sublen += 1LL * (len[i] + len[fail[i]] + 1) * (len[i] - len[fail[i]]) / 2;
    121     }
    122 
    123     void get_sa() { //获取sa数组
    124         for (int i = 1; i <= tot; i++) c[len[i]]++;
    125         for (int i = 1; i <= tot; i++) c[i] += c[i - 1];
    126         for (int i = tot; i >= 1; i--) sa[c[len[i]]--] = i;
    127     }
    128 
    129     int cntnum[maxn << 1];
    130 
    131     void match() {//多个串的最长公共子串
    132         mem(cntnum, 0);
    133         int n = strlen(s), p = 1, ans = INF;
    134         for (int i = 0; i < n; i++) {
    135             int c = s[i] - 'a';
    136             if (nxt[p][c]) p = nxt[p][c];
    137             else {
    138                 for (; p && !nxt[p][c]; p = fail[p]);
    139                 if (!p) p = 1;
    140                 else p = nxt[p][c];
    141             }
    142             cntnum[p]++;
    143         }
    144         for (int i = tot; i; i--) cntnum[fail[Y[i]]] += cntnum[Y[i]];
    145         for (int i = 2; i <= tot; i++)
    146             if (num[i] == 1 && cntnum[i] == 1) ans = min(ans, len[fail[i]] + 1);
    147         if (ans == INF) printf("-1
    ");
    148         else printf("%d
    ", ans);
    149     }
    150 
    151     void get_kth(int k) {//求出字典序第K的子串
    152         int pos = 1, cnt;
    153         string s = "";
    154         while (k) {
    155             for (int i = 0; i <= 25; i++) {
    156                 if (nxt[pos][i] && k) {
    157                     cnt = nxt[pos][i];
    158                     if (sum[cnt] < k) k -= sum[cnt];
    159                     else {
    160                         k--;
    161                         pos = cnt;
    162                         s += (char) (i + 'a');
    163                         break;
    164                     }
    165                 }
    166             }
    167         }
    168         cout << s << endl;
    169     }
    170 
    171 } sam;
    172 
    173 int main() {
    174 #ifndef ONLINE_JUDGE
    175     FIN;
    176 #endif
    177     sam.init();
    178     sfs(s + 1);
    179     int n = strlen(s + 1);
    180     for (int i = 1; i <= n; i++) sam.extend((s[i] - 'a'));
    181     sfs(s);
    182     sam.get_num();
    183     sam.match();
    184 #ifndef ONLINE_JUDGE
    185     cout << "Totle Time : " << (double) clock() / CLOCKS_PER_SEC << "s" << endl;
    186 #endif
    187     return 0;
    188 }
    View Code
  • 相关阅读:
    Java实现 LeetCode 69 x的平方根
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 66 加一
    Java实现 LeetCode 66 加一
    CxSkinButton按钮皮肤类
  • 原文地址:https://www.cnblogs.com/qldabiaoge/p/11566941.html
Copyright © 2011-2022 走看看