码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 3294 二分找超过一半字符串中存在的子串

时间:2016-01-22 03:08:35      阅读:167      评论:0      收藏:0      [点我收藏+]

标签:

题目大意:

给定n个字符串,求出现在不小于k/2个字符串中的最长子串。 

 

二分找对应子串长度的答案,将所有字符串链接成一个长字符串求后缀数组,记录每一个位置本属于第几个字符串,利用height查询的时候,

根据记录的位置不断判断是否出现重复的字符串是在同一个字符串内的

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <vector>
  4 #include <iostream>
  5 using namespace std;
  6 typedef long long ll;
  7 const int N = 200010;
  8 int r[N] , sa[N] , rank[N] , height[N];
  9 int K , wa[N] , wb[N] , wv[N] , wsf[N];
 10 int cmp(int *r , int a , int b , int l){return r[a]==r[b]&&r[a+l]==r[b+l];}
 11 void da(int *r , int *sa , int n , int m)
 12 {
 13     int i,j,p,*x=wa,*y=wb,*t;
 14     for(i=0;i<m;i++)wsf[i]=0;
 15     for(i=0;i<n;i++)wsf[x[i]=r[i]]++;
 16     for(i=1 ; i<m ; i++) wsf[i]+=wsf[i-1];
 17     for(i=n-1;i>=0;i--) sa[--wsf[x[i]]]=i;
 18     for(j=1,p=1;p<n;j*=2,m=p){
 19         for(p=0,i=n-j;i<n;i++) y[p++]=i;
 20         for(i=0;i<n;i++) if(sa[i]>=j)y[p++]=sa[i]-j;
 21         for(i=0;i<n;i++) wv[i]=x[y[i]];
 22         for(i=0;i<m;i++) wsf[i]=0;
 23         for(i=0;i<n;i++) wsf[wv[i]]++;
 24         for(i=1;i<m;i++) wsf[i]+=wsf[i-1];
 25         for(i=n-1;i>=0;i--) sa[--wsf[wv[i]]]=y[i];
 26         for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
 27             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
 28     }
 29     return;
 30 }
 31 void callHeight(int *r , int *sa , int n)
 32 {
 33     int i,j,k=0;
 34     for(i=1;i<=n;i++) rank[sa[i]]=i;
 35     for(i=0;i<n;height[rank[i++]]=k)
 36         for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
 37     return;
 38 }
 39 #define ll long long
 40 int n , len , pos[105][2] , dif , mp[N];
 41 bool vis[105];
 42 char s[105][1005] , all[N];
 43 vector<int> ans , tmp;
 44 bool check(int mid)
 45 {
 46     tmp.clear();
 47     bool flag = false;
 48     memset(vis , 0 , sizeof(vis));
 49     int cnt = 1 , rec = sa[0];
 50     vis[sa[0]] = true;
 51     for(int i=1 ; i<len ; i++){
 52         if(height[i]<mid){
 53             if(cnt>n/2){
 54                 tmp.push_back(rec);
 55                 flag = true;
 56             }
 57             memset(vis , 0 , sizeof(vis));
 58             cnt = 1 , vis[mp[sa[i]]] = true , rec = sa[i];
 59         }
 60         else{
 61             if(!vis[mp[sa[i]]]){
 62                 vis[mp[sa[i]]] = true;
 63                 cnt++;
 64                 rec = sa[i];
 65             }
 66         }
 67     }
 68     if(flag) ans = tmp;
 69     return flag;
 70 }
 71 int bin_search()
 72 {
 73     int l=0 , r=1000 , ans=0 , mid;
 74     while(l<=r){
 75         mid = (l+r)>>1;
 76         if(check(mid)) l=mid+1 , ans=mid;
 77         else r=mid-1;
 78     }
 79     return ans;
 80 }
 81 int main()
 82 {
 83    // freopen("a.in" , "r" , stdin);
 84     bool flag = false;
 85     while(scanf("%d" , &n) , n){
 86         if(flag) puts("");
 87         flag = true;
 88         len = 0 , dif = 27;
 89         for(int i=0 ; i<n ; i++){
 90             scanf("%s" , s[i]);
 91             for(int j=0 ; j<strlen(s[i]) ; j++) all[len] = s[i][j] , mp[len]=i+1 , r[len++] = s[i][j]-a+1;
 92             pos[i][0] = len;
 93             all[len] = *;
 94             mp[len]=i+1 , r[len++] = dif++;
 95         }
 96         r[len-1] = 0;
 97         da(r , sa , len , dif);
 98        // for(int i=0 ; i<len ; i++) cout<<"i: "<<i<<" "<<sa[i]<<endl;
 99         callHeight(r , sa , len-1);
100         int ret = bin_search();
101         if(!ret) puts("?");
102         else{
103             for(int i=0 ; i<ans.size() ; i++){
104                 for(int j=ans[i] , t=0 ; t<ret ; j++ , t++) printf("%c" , all[j]);
105                 puts("");
106             }
107         }
108     }
109 }

 

POJ 3294 二分找超过一半字符串中存在的子串

标签:

原文地址:http://www.cnblogs.com/CSU3901130321/p/5150118.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!