zoukankan      html  css  js  c++  java
  • [POI2000]公共串

    Update 2018.1.8:sto lsy orz 给出了一个 (O(n)) 的做法。

    Description

    求若干个串的最长的公共子串的长度。

    Solution

    考虑将这若干个串全部拼起来,中间用一些不在字符集内的符号隔开。

    然后二分答案 (K),如果连续的一段 (height) 都大于等于 (K),且每个串都出现了至少一次,则是可行的。

    O(N)

    并没有必要二分答案,前面是二分长度,然后 (check) 一下是否有一段连续的 (height) 区间使得每个值都大于等于 (K),且每个串都出现至少一次。

    反过来,我们可以枚举左端点,然后不断向右扩展右端点,当每种串都出现恰好至少一次时,就对把答案和这一段区间的 (min) 取个 (max),然后区间的 (min) 用单调队列维护即可。

    然后可能是由于我的代码比较丑陋,且在洛谷上此题数据范围比较小,我的 (O(N)) 居然跑得比 (O(Nlog N)) 慢。(笑

    Code

    O(NlogN)​

    #include <bits/stdc++.h>
    using namespace std;
    
    const int _ = 1e5 + 10;
    int N, n, s[_], belong[_];
    int rnk[_], sa[_], height[_];
    char str[_];
    
    void SA() {
    	static int t[_], a[_], buc[_], fir[_], sec[_], tmp[_];
    	copy(s + 1, s + N + 1, t + 1);
    	sort(t + 1, t + N + 1);
    	int *end = unique(t + 1, t + N + 1);
    	for (int i = 1; i <= N; ++i) a[i] = lower_bound(t + 1, end, s[i]) - t;
    	fill(buc + 1, buc + N + 1, 0);
    	for (int i = 1; i <= N; ++i) ++buc[a[i]];
    	for (int i = 1; i <= N; ++i) buc[i] += buc[i - 1];
    	for (int i = 1; i <= N; ++i) rnk[i] = buc[a[i] - 1] + 1;
    	for (int len = 1; len <= N; len <<= 1) {
    		for (int i = 1; i <= N; ++i) {
    			fir[i] = rnk[i];
    			sec[i] = i + len > N ? 0 : rnk[i + len];
    		}
    		fill(buc + 1, buc + N + 1, 0);
    		for (int i = 1; i <= N; ++i) ++buc[sec[i]];
    		for (int i = 1; i <= N; ++i) buc[i] += buc[i - 1];
    		for (int i = 1; i <= N; ++i) tmp[N - --buc[sec[i]]] = i;
    		fill(buc + 1, buc + N + 1, 0);
    		for (int i = 1; i <= N; ++i) ++buc[fir[i]];
    		for (int i = 1; i <= N; ++i) buc[i] += buc[i - 1];
    		for (int i, j = 1; j <= N; ++j) {
    			i = tmp[j];
    			sa[buc[fir[i]]--] = i;
    		}
    		bool same = false;
    		for (int i, j = 1, last = 0; j <= N; ++j) {
    			i = sa[j];
    			if (!last) rnk[i] = 1;
    			else if (fir[i] == fir[last] && sec[i] == sec[last])
    				rnk[i] = rnk[last], same = true;
    			else rnk[i] = rnk[last] + 1;
    			last = i;
    		}
    		if (!same) break;
    	}
    	for (int i = 1, k = 0; i <= N; ++i) {
    		if (rnk[i] == 1) k = 0;
    		else {
    			if (k > 0) --k;
    			int j = sa[rnk[i] - 1];
    			while (i + k <= N && j + k <= N && a[i + k] == a[j + k]) ++k;
    		}
    		height[rnk[i]] = k;
    	}
    }
    
    
    bool check(int k) {
    	static int vis[_], tot = 0;
    	int cnt = 0;
    	++tot;
    	for (int i = 1; i <= N; ++i) {
    		if (height[i] < k) cnt = 0, ++tot;
    		else {
    			if (vis[belong[sa[i]]] != tot)
    				vis[belong[sa[i]]] = tot, ++cnt;
    			if (vis[belong[sa[i - 1]]] != tot)
    				vis[belong[sa[i - 1]]] = tot, ++cnt;
    			if (cnt == n) return true;
    		}
    	}
    	return false;
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("string.in", "r", stdin);
    	freopen("string.out", "w", stdout);
    #endif
    	scanf("%d", &n);
    	int now = 0;
    	for (int i = 1; i <= n; ++i) {
    		++now;
    		scanf("%s", str);
    		int len = strlen(str);
    		for (int j = now; j <= now + len - 1; ++j)
    			s[j] = str[j - now] - 'a' + 1, belong[j] = i;
    		now += len - 1;
    		s[++now] = i + 26;
    	}
    	N = now;
    	SA();
    	int l = 0, r = N;
    	while (l < r) {
    		int mid = (l + r + 1) >> 1;
    		if (check(mid)) l = mid;
    		else r = mid - 1;
    	}
    	printf("%d
    ", l);
    	return 0;
    }
    

    O(N)

    #include <bits/stdc++.h>
    using namespace std;
    
    const int _ = 1e5 + 10;
    const int INF = 0x3f3f3f3f;
    int N, n, s[_], belong[_];
    int rk[_], sa[_], height[_];
    char str[_];
    
    inline void SA() {
      int M = 125, p = 0;  // 字符集
      static int buc[_], id[_], fir[_], t[_], oldrk[_];
      copy(s + 1, s + N + 1, t + 1);
      sort(t + 1, t + N + 1);
      int *end = unique(t + 1, t + N + 1);
      for (int i = 1; i <= N; ++i) s[i] = lower_bound(t + 1, end, s[i]) - t;
      for (int i = 1; i <= N; ++i) ++buc[rk[i] = s[i]];
      for (int i = 1; i <= M; ++i) buc[i] += buc[i - 1];
      for (int i = N; i >= 1; --i) sa[buc[rk[i]]--] = i;
      for (int w = 1; w < N; w <<= 1, M = p) {
        p = 0;
        for (int i = N; i > N - w; --i) id[++p] = i;
        for (int i = 1; i <= N; ++i)
          if (sa[i] > w) id[++p] = sa[i] - w;
        fill(buc + 1, buc + M + 1, 0);
        for (int i = 1; i <= N; ++i) ++buc[fir[i] = rk[id[i]]];
        for (int i = 1; i <= M; ++i) buc[i] += buc[i - 1];
        for (int i = N; i >= 1; --i) sa[buc[fir[i]]--] = id[i];
        copy(rk + 1, rk + N + 1, oldrk + 1);
        p = 0;
        for (int i = 1; i <= N; ++i) {
          int x = sa[i], y = sa[i - 1];
          rk[sa[i]] =
              (oldrk[x] == oldrk[y] && oldrk[x + w] == oldrk[y + w]) ? p : ++p;
        }
        if (p == N) break;
      }
      for (int i = 1, k = 0; i <= N; ++i) {
        if (rk[i] == 1)
          k = 0;
        else {
          if (k > 0) --k;
          int j = sa[rk[i] - 1];
          while (i + k <= N && j + k <= N && s[i + k] == s[j + k]) ++k;
        }
        height[rk[i]] = k;
      }
    }
    
    int ans = 0;
    void solve() {
      static int vis[_], cnt = 0;
      static int q[_];
      int l = 1, r = 1;
      for (int i = 1, j = 1; i <= N; ++i) {
        while (l < r && q[l] < i) ++l;
        while (j <= N && cnt < n) {
          if (!vis[belong[sa[j]]]) ++cnt;
          ++vis[belong[sa[j]]];
          while (l < r && height[q[r - 1]] >= height[j]) --r;
          q[r++] = j;
          ++j;
        }
        if (cnt == n)
          ans = max(ans, height[q[l]]);
        else
          return;
        if (i - 1 > 0) {
          --vis[belong[sa[i - 1]]];
          if (!vis[belong[sa[i - 1]]]) --cnt;
        }
      }
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
      freopen("string.in", "r", stdin);
      freopen("string.out", "w", stdout);
    #endif
      scanf("%d", &n);
      int now = 0;
      for (int i = 1; i <= n; ++i) {
        ++now;
        scanf("%s", str);
        int len = strlen(str);
        for (int j = now; j <= now + len - 1; ++j)
          s[j] = str[j - now] - 'a' + 1, belong[j] = i;
        now += len - 1;
        s[++now] = i + 26;
      }
      N = now;
      SA();
      solve();
      printf("%d
    ", ans);
      return 0;
    }
    
  • 相关阅读:
    shell语句for循环
    ls命令详解
    计算机相关概念总结(3)
    计算机相关概念总结(2)
    计算机相关概念总结(1)
    devops的概念
    jenkins无法连接gitlab
    Jenkins创建镜像后无法推送到harbor的问题
    Jenkins+gitlab+maven持续集成
    jenkins打完包在哪里
  • 原文地址:https://www.cnblogs.com/newbielyx/p/12160645.html
Copyright © 2011-2022 走看看