• Boring counting HDU


    Boring counting

    [Time Limit: 1000 ms quad Memory Limit: 32768 kB ]

    题意

    给出一个字符串,求出其中出现两次及以上的子串个数,要求子串之间不可以重合。

    思路

    对字符串后缀数组,然后枚举子串长度 (len),若某一段连续的 (sa[i])(lcp geq len),那么说明这一段内存在一个长度为 (lcp) 的子串,而我们只需要其中的前 (len) 部分,接下来只要找出这个子串出现的最左和最右位置,然后判断中间能否放下这个长度为 (len) 的子串就可以了,如果可以的话,就让 (ans)++。


    (Hint)
    这题还让我学到后缀数组的另一个细节,在构建后缀数组之前,要在末尾加上一个比所有字符都小的字符,因为在求 (height) 的时候需要判断 (a[i+k]==a[j+k]),否则这里可能会无限扩展下去。

    /***************************************************************
        > File Name    : a.cpp
        > Author       : Jiaaaaaaaqi
        > Created Time : 2019年05月23日 星期四 22时40分17秒
     ***************************************************************/
    
    #include <map>
    #include <set>
    #include <list>
    #include <ctime>
    #include <cmath>
    #include <stack>
    #include <queue>
    #include <cfloat>
    #include <string>
    #include <vector>
    #include <cstdio>
    #include <bitset>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define  lowbit(x)  x & (-x)
    #define  mes(a, b)  memset(a, b, sizeof a)
    #define  fi         first
    #define  se         second
    #define  pii        pair<int, int>
    
    typedef unsigned long long int ull;
    typedef long long int ll;
    const int    maxn = 1e5 + 10;
    const int    maxm = 1e5 + 10;
    const ll     mod  = 1e9 + 7;
    const ll     INF  = 1e18 + 100;
    const int    inf  = 0x3f3f3f3f;
    const double pi   = acos(-1.0);
    const double eps  = 1e-8;
    using namespace std;
    
    int n, m;
    int cas, tol, T;
    
    char s[maxn];
    int a[maxn], sa[maxn], tp[maxn], tax[maxn], rk[maxn], height[maxn];
    
    void rsort(int n, int m) {
    	for(int i=0; i<=m; i++)	tax[i] = 0;
    	for(int i=1; i<=n; i++)	tax[rk[tp[i]]]++;
    	for(int i=1; i<=m; i++)	tax[i] += tax[i-1];
    	for(int i=n; i>=1; i--)	sa[tax[rk[tp[i]]]--] = tp[i];
    }
    
    int cmp(int *f, int x, int y, int w) {
    	return f[x]==f[y] && f[x+w]==f[y+w];
    }
    
    void SA(int *a, int n, int m) {
    	for(int i=1; i<=n; i++)	rk[i] = a[i], tp[i] = i;
    	rsort(n, m);
    	for(int w=1, p=1, i; p<n; w<<=1, m=p) {
    		for(p=0, i=n-w+1; i<=n; i++)	tp[++p] = i;
    		for(i=1; i<=n; i++)	if(sa[i] > w)	tp[++p] = sa[i]-w;
    		rsort(n, m), swap(rk, tp);
    		rk[sa[1]] = p = 1;
    		for(i=2; i<=n; i++)	rk[sa[i]] = cmp(tp, sa[i], sa[i-1], w) ? p : ++p;
    	}
    	int j, k=0;
    	for(int i=1; i<=n; height[rk[i++]] = k)
    		for(k = k ? k-1 : k, j=sa[rk[i]-1]; a[i+k]==a[j+k]; k++);
    }
    
    int calc(int len) {
    	int ans = 0;
    	int mx, mn;
    	mx = -inf, mn = inf;
    	for(int i=2; i<=n; i++) {
    		if(height[i]>=len) {
    			mx = max(mx, max(sa[i], sa[i-1]));
    			mn = min(mn, min(sa[i], sa[i-1]));
    		} else {
    			if(mx - mn >= len)	ans++;
    			mx = -inf, mn = inf;
    		}
    	}
    	if(mx - mn >= len)	ans++;
    	return ans;
    }
    
    int main() {
    	while(scanf("%s", s+1)) {
    		if(s[1] == '#')	break;
    		n = strlen(s+1);
    		s[++n] = 2;
    		for(int i=1; i<=n; i++) {
    			a[i] = s[i];
    		}
    		SA(a, n, 260);
    		// for(int i=1; i<=n; i++) {
    		//     printf("sa[%d] = %d
    ", i, sa[i]);
    		// }
    		int ans = 0;
    		for(int i=1; i<=(n+1)/2; i++) {
    			ans += calc(i);
    		}
    		printf("%d
    ", ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    [codevs 1243][网络提速(最短路分层思想)
    [codevs 1183][泥泞的道路(二分+spfa)
    [codevs 2488]绿豆蛙的归宿(拓扑排序)
    [codevs 1961]躲避大龙(dfs)
    4、userCF和itemCF对比,冷启动
    query简洁弹出层代码
    css 积累1
    localStorage,sessionStorage
    tr th td
    (转存)面向切面编程(AOP)的理解
  • 原文地址:https://www.cnblogs.com/Jiaaaaaaaqi/p/10915328.html
Copyright © 2020-2023  润新知