[HDU2328]Corporate Identity(后缀数组)

传送门

求 n 个串的字典序最小的最长公共子串。

和 2 个串的处理方法差不多。

把 n 个串拼接在一起,中间连上一个没有出现过的字符防止匹配过界。

求出 height 数组后二分公共子串长度给后缀数组分组。

然后 check,每一组中是否所有的字符串都包含。

直接遍历 sa 数组,第一个满足的结果就是字典序最小的。

——代码

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #define N 900005
  5 #define M 4001
  6
  7 int n, len, m, start;
  8 int buc[N], x[N], y[N], sa[N], rank[N], height[N], belong[N];
  9 char s[N], a[M];
 10 bool f[M];
 11
 12 inline void build_sa()
 13 {
 14     int i, k, p;
 15     for(i = 0; i < m; i++) buc[i] = 0;
 16     for(i = 0; i < len; i++) buc[x[i] = s[i]]++;
 17     for(i = 1; i < m; i++) buc[i] += buc[i - 1];
 18     for(i = len - 1; i >= 0; i--) sa[--buc[x[i]]] = i;
 19     for(k = 1; k <= len; k <<= 1)
 20     {
 21         p = 0;
 22         for(i = len - 1; i >= len - k; i--) y[p++] = i;
 23         for(i = 0; i < len; i++) if(sa[i] >= k) y[p++] = sa[i] - k;
 24         for(i = 0; i < m; i++) buc[i] = 0;
 25         for(i = 0; i < len; i++) buc[x[y[i]]]++;
 26         for(i = 1; i < m; i++) buc[i] += buc[i - 1];
 27         for(i = len - 1; i >= 0; i--) sa[--buc[x[y[i]]]] = y[i];
 28         std::swap(x, y);
 29         p = 1, x[sa[0]] = 0;
 30         for(i = 1; i < len; i++)
 31             x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++;
 32         if(p >= len) break;
 33         m = p;
 34     }
 35 }
 36
 37 inline void build_height()
 38 {
 39     int i, j, k = 0;
 40     for(i = 0; i < len; i++) rank[sa[i]] = i;
 41     for(i = 0; i < len; i++)
 42     {
 43         if(!rank[i]) continue;
 44         if(k) k--;
 45         j = sa[rank[i] - 1];
 46         while(s[i + k] == s[j + k] && i + k < len && j + k < len) k++;
 47         height[rank[i]] = k;
 48     }
 49 }
 50
 51 inline bool check(int k)
 52 {
 53     int i, cnt = 1;
 54     memset(f, 0, sizeof(f));
 55     f[belong[sa[0]]] = 1;
 56     for(i = 1; i < len; i++)
 57         if(height[i] >= k)
 58         {
 59             if(!f[belong[sa[i]]]) cnt++;
 60             f[belong[sa[i]]] = 1;
 61             if(cnt == n)
 62             {
 63                 start = sa[i];
 64                 return 1;
 65             }
 66         }
 67         else
 68         {
 69             memset(f, 0, sizeof(f));
 70             f[belong[sa[i]]] = 1;
 71             cnt = 1;
 72         }
 73     return 0;
 74 }
 75
 76 int main()
 77 {
 78     int i, j, l, r, mid, leng;
 79     while(scanf("%d", &n) && n)
 80     {
 81         len = 0;
 82         m = 256;
 83         memset(belong, 0, sizeof(belong));
 84         for(i = 1; i <= n; i++)
 85         {
 86             scanf("%s", a);
 87             for(j = 0; a[j] ^ ‘\0‘; j++) s[len++] = a[j];
 88             s[len++] = ‘#‘;
 89             belong[len] = 1;
 90         }
 91         len--;
 92         build_sa();
 93         build_height();
 94         for(i = 1; i < len; i++) belong[i] += belong[i - 1];
 95         l = 1, r = len, leng = 0, start = -1;
 96         while(l <= r)
 97         {
 98             mid = (l + r) >> 1;
 99             if(check(mid)) leng = mid, l = mid + 1;
100             else r = mid - 1;
101         }
102         if(leng && start ^ -1)
103         {
104             for(i = start; i < start + leng; i++) putchar(s[i]);
105             putchar(‘\n‘);
106         }
107         else puts("IDENTITY LOST");
108     }
109     return 0;
110 } 

时间: 2024-10-18 06:55:37

[HDU2328]Corporate Identity(后缀数组)的相关文章

poj 3518 Corporate Identity 后缀数组-&gt;多字符串最长相同连续子串

题目链接 题意:输入N(2 <= N <= 4000)个长度不超过200的字符串,输出字典序最小的最长公共连续子串; 思路:将所有的字符串中间加上分隔符,注:分隔符只需要和输入的字符不同,且各自不同即可,没有必要是最小的字符; 连接后缀数组求解出height之后二分长度,由于height是根据sa数组建立的,所以前面符合的就是字典序最小的,直接找到就停止即可; ps: 把之前的模板简化了下,A题才是关键; #include<iostream> #include<cstdio&

hdu2328 Corporate Identity【string库使用】【暴力】【KMP】

Corporate Identity Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3308    Accepted Submission(s): 1228 Problem Description Beside other services, ACM helps companies to clearly state their "cor

hdu2328 Corporate Identity 扩展KMP

Beside other services, ACM helps companies to clearly state their "corporate identity", which includes company logo but also other signs, like trademarks. One of such companies is Internet Building Masters (IBM), which has recently asked ACM for

POJ-3450 Corporate Identity (KMP+后缀数组)

Description Beside other services, ACM helps companies to clearly state their "corporate identity", which includes company logo but also other signs, like trademarks. One of such companies is Internet Building Masters (IBM), which has recently a

hdu2328(后缀数组 + 二分)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2328 题意: 求 n 个串的字典序最小的最长公共子串 思路: 本题中单个字符串长度不超过 200, 可以暴力枚举一个字符串的所有前缀, 然后用kmp去匹配其他字符串. 我这里是用后缀数组写的. 类似 http://www.cnblogs.com/geloutingyu/p/7450580.html 不过本题是有 n 个字符串, 不能直接暴力判断. 不难想到这里可以直接二分答案长度, 不过 chec

kuangbin带你飞 后缀数组 题解

2份模板 DC3 . 空间复杂度O3N 时间复杂度On #define F(x) ((x) / 3 + ((x) % 3 == 1 ? 0 : tb)) #define G(x) ((x) < tb ? (x) * 3 + 1 :((x) - tb) * 3 + 2) const int MAXN = 300010; const int MAXM = 100010; char input[MAXM]; int wa[MAXN],wb[MAXN],ws[MAXN],wv[MAXN],wsd[MAX

【后缀数组|最长回文子串】URAL-1297 Palindrome

1297.Palindrome Time limit: 1.0 second Memory limit: 64 MB The "U.S. Robots" HQ has just received a rather alarming anonymous letter. It states that the agent from the competing ?Robots Unlimited? has infiltrated into "U.S. Robotics".

Ural 1297 Palindrome(Manacher或者后缀数组+RMQ-ST)

1297. Palindrome Time limit: 1.0 second Memory limit: 64 MB The “U.S. Robots” HQ has just received a rather alarming anonymous letter. It states that the agent from the competing «Robots Unlimited» has infiltrated into “U.S. Robotics”. «U.S. Robots»

URAL 1297 Palindrome 后缀数组

1297. Palindrome Time limit: 1.0 second Memory limit: 64 MB The "U.S. Robots" HQ has just received a rather alarming anonymous letter. It states that the agent from the competing ?Robots Unlimited? has infiltrated into "U.S. Robotics".