• POJ3294 Life Forms(后缀数组)


    引用罗穗骞论文中的话:

    将n 个字符串连起来,中间用不相同的且没有出现在字符串中的字符隔开,求后缀数组。然后二分答案,用和例3 同样的方法将后缀分成若干组,判断每组的后缀是否出现在不小于k 个的原串中。这个做法的时间复杂度为O(nlogn)。

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    
    using namespace std;
    const int N = 110008;
    int wa[N],wb[N],wv[N],ws0[N];
    int val[N], sum[N], tp1[N], tp2[N];
    int sa[N], rank[N], height[N];
    int hs[N];
    
    char tp[1008];
    int str[N];
    bool vis[1000];
    
    vector<int> v;
    
    int cmp(int *r,int a,int b,int l)
    {return r[a]==r[b]&&r[a+l]==r[b+l];}
    void da(int *r,int *sa,int n,int m)
    {
         int i,j,p,*x=wa,*y=wb,*t;
         for(i=0;i<m;i++) ws0[i]=0;
         for(i=0;i<n;i++) ws0[x[i]=r[i]]++;
         for(i=1;i<m;i++) ws0[i]+=ws0[i-1];
         for(i=n-1;i>=0;i--) sa[--ws0[x[i]]]=i;
         for(j=1,p=1;p<n;j*=2,m=p)
         {
           for(p=0,i=n-j;i<n;i++) y[p++]=i;
           for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
           for(i=0;i<n;i++) wv[i]=x[y[i]];
           for(i=0;i<m;i++) ws0[i]=0;
           for(i=0;i<n;i++) ws0[wv[i]]++;
           for(i=1;i<m;i++) ws0[i]+=ws0[i-1];
           for(i=n-1;i>=0;i--) sa[--ws0[wv[i]]]=y[i];
           for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
           x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
         }
         return;
    }
    void calheight(int *r,int *sa,int n)
    {
         int i,j,k=0;
         for(i=1;i<=n;i++) rank[sa[i]]=i;
         for(i=0;i<n;height[rank[i++]]=k)
         for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
         return;
    }
    
    bool check(int m, int n, int num){
    	memset(vis , 0, sizeof(vis));
    	int cnt = 0;
    	int size = 0;
    	for(int i = 1; i <= n ;i++){
    		if(height[i] >= m){//分组,同组内计数
    		    if(!vis[hs[ sa[i] ]]){
    				cnt++;
    				vis[hs[ sa[i] ]] = 1;
    			}
    
    			if(!vis[hs[ sa[i - 1] ]]){//不同组
    				cnt++;
    				vis[hs[ sa[i - 1] ]] = 1;
    			}
    
    		}else{
    			if(cnt > num){
    				if(size == 0){
    					v.clear();
    				}
    				size++;
    				v.push_back(sa[i - 1]);
    			}
    			cnt = 0;
                memset(vis, 0 , sizeof(vis));
    
    		}
    	}
    	if(size){
    		return true;
    	}else{
    		return false;
    	}
    
    }
    
    
    int main(){
        int k;
        bool flag = 0;
        while(~scanf("%d", &k ) && k){
                v.clear();
        	int n = 0;
        	int mini = 100000000;
        	for(int t = 0; t < k; t++){
        		scanf("%s", tp);
        		int len = strlen(tp);
        		mini = min(mini, len);
        		for(int i = n, j = 0; j < len; i++, j++){
        			str[i]  = tp[j];
        			hs[i] = t;
        		}
        		n += len + 1;
        		if(t != k - 1){
        			str[n - 1] = t + 130;
        		}
        	}
        	n--;
        	str[n] = 0;
            da(str, sa , n + 1 , 256);
        	calheight(str, sa, n);
        	int l = 1, r = mini;
        	int ans = 0;
        	while(l <= r){
        		int m = (l + r)>>1;
        		if(check(m, n, k / 2 )){
        			l = m + 1;
        			ans = m;
        		}else{
        			r = m - 1;
        		}
        	}
        	if(flag){
        		printf("
    ");
        	}
        	flag = 1;
        	if(ans){
        		for(int i = 0; i < v.size(); i++){
        			int st = v[i];
        			for(int j = 0; j < ans; j++){
        				printf("%c", str[st + j]);
        			}
        			printf("
    ");
        		}
        	}else{
        		printf("?
    ");
        	}
    
        }
        return 0;
    }
    

      

  • 相关阅读:
    重新看待Jar包冲突问题及解决方案
    一步步完成Maven+SpringMVC+SpringFox+Swagger整合示例
    [ACM] POJ 1611 The Suspects (并查集,输出第i个人所在集合的总人数)
    James Whittaker的软件測试戒律(二)
    <html>
    andorid ndk 各种坑啊 记录下
    Android的ProgressBar进度条-android学习之旅(三十一)
    Android Jsoup 爬取网页数据
    iOS笔记UI--使用storyboard加入约束
    使用appledoc 生成技术API文档具体解释
  • 原文地址:https://www.cnblogs.com/IMGavin/p/5733733.html
Copyright © 2020-2023  润新知