POJ - 3294 Life Forms

1.题面

http://poj.org/problem?id=3294

2.题意

给你n个字符串,希望你求出一个长度最长的子串s,s在至少n/2个字符串中出现过,

3.思路

将所有的数字连在一起后使用后缀数组,二分答案

第二种方法也是先用后缀数组处理,后面使用一个尺取法

二分   800+ms

尺取法  1200+ms

我觉得set的常数产生了很大的影响

4.代码

二分代码

/*****************************************************************
    > File Name: Cpp_Acm.cpp
    > Author: Uncle_Sugar
    > Mail: uncle_sugar@qq.com
    > Created Time: 2016年08月01日 星期一 18时50分27秒
*****************************************************************/
# include <cstdio>
# include <cstring>
# include <cctype>
# include <cmath>
# include <cstdlib>
# include <climits>
# include <iostream>
# include <iomanip>
# include <set>
# include <map>
# include <vector>
# include <stack>
# include <queue>
# include <algorithm>
using namespace std;

# define rep(i,a,b) for (i=a;i<=b;i++)
# define rrep(i,a,b) for (i=b;i>=a;i--)


template<class T>void PrintArray(T* first,T* last,char delim=' '){ 
	for (;first!=last;first++) cout << *first << (first+1==last?'\n':delim); 
}

const int debug = 1;
const int size  = 1000 + 300000 ; 
const int INF = INT_MAX>>1;
typedef long long ll;

const int MAXN = 500000 + 1000;  
#define F(x) ((x)/3+((x)%3==1?0:tb))  
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)  
int wa[MAXN*3],wb[MAXN*3],wv[MAXN*3],wss[MAXN*3];  
int c0(int *r,int a,int b)  
{  
    return r[a] == r[b] && r[a+1] == r[b+1] && r[a+2] == r[b+2];  
}  
int c12(int k,int *r,int a,int b)  
{  
    if(k == 2)  
        return r[a] < r[b] || ( r[a] == r[b] && c12(1,r,a+1,b+1) );  
    else return r[a] < r[b] || ( r[a] == r[b] && wv[a+1] < wv[b+1] );  
}  
void sort(int *r,int *a,int *b,int n,int m)  
{  
    int i;  
    for(i = 0;i < n;i++)wv[i] = r[a[i]];  
    for(i = 0;i < m;i++)wss[i] = 0;  
    for(i = 0;i < n;i++)wss[wv[i]]++;  
    for(i = 1;i < m;i++)wss[i] += wss[i-1];  
    for(i = n-1;i >= 0;i--)  
        b[--wss[wv[i]]] = a[i];  
}  
void dc3(int *r,int *sa,int n,int m)  
{  
    int i, j, *rn = r + n;  
    int *san = sa + n, ta = 0, tb = (n+1)/3, tbc = 0, p;  
    r[n] = r[n+1] = 0;  
    for(i = 0;i < n;i++)if(i %3 != 0)wa[tbc++] = i;  
    sort(r + 2, wa, wb, tbc, m);  
    sort(r + 1, wb, wa, tbc, m);  
    sort(r, wa, wb, tbc, m);  
    for(p = 1, rn[F(wb[0])] = 0, i = 1;i < tbc;i++)  
        rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p - 1 : p++;  
    if(p < tbc)dc3(rn,san,tbc,p);  
    else for(i = 0;i < tbc;i++)san[rn[i]] = i;  
    for(i = 0;i < tbc;i++) if(san[i] < tb)wb[ta++] = san[i] * 3;  
    if(n % 3 == 1)wb[ta++] = n - 1;  
    sort(r, wb, wa, ta, m);  
        for(i = 0;i < tbc;i++)wv[wb[i] = G(san[i])] = i;  
    for(i = 0, j = 0, p = 0;i < ta && j < tbc;p++)  
        sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++];  
    for(;i < ta;p++)sa[p] = wa[i++];  
    for(;j < tbc;p++)sa[p] = wb[j++];  
}  
//str和sa也要三倍  
void da(int str[],int sa[],int rank[],int height[],int n,int m)  
{  
    for(int i = n;i < n*3;i++)  
        str[i] = 0;  
    dc3(str, sa, n+1, m);  
    int i,j,k = 0;  
    for(i = 0;i <= n;i++)rank[sa[i]] = i;  
    for(i = 0;i < n; i++)  
    {  
        if(k) k--;  
        j = sa[rank[i]-1];  
        while(str[i+k] == str[j+k]) k++;  
        height[rank[i]] = k;  
    }  
}  
int sa[size],rrank[size],height[size];  
  
int n,k;      
  
int str[size],len; 
int zone[size];
char s[size];

int vis[200];
queue<int> que;
bool isok(int ll){
	memset(vis,0,sizeof(vis));
	while (!que.empty()) que.pop();
	que.push(zone[sa[1]]);
	vis[zone[sa[1]]] = 1;
	//# for (int i=1;i<=n;i++){
		//# cout << height[i] << (i==n?'\n':' ');
	//# }
	//# cout << endl;
	for (int i=2;i<=len;i++){
		//# cout << "height " << i << " " << height[i] << endl;
		if (height[i]>=ll){
			if (vis[zone[sa[i]]]==0){
				que.push(zone[sa[i]]);
				vis[zone[sa[i]]] = 1;
			}
		}else {
			//# cout << "que.size = " << que.size() << endl; 
			if (que.size()>n/2) return true;
			while (!que.empty()){
				vis[que.front()] = 0;
				que.pop();
			}
			que.push(zone[sa[i]]);
			vis[zone[sa[i]]] = 1;
		}
	}
	if (que.size()>n/2)
		return true;
	return false;
}

void Debug(int n){
	for (int i=1;i<=n;i++){
		cout << "*" << i << "*\t" << height[i] << "\t" << zone[sa[i]] << '\t';
		PrintArray(str+sa[i],str+n,'\t');
	}
}

int main()  
{  
    int i,j;  
	int ncase = 0;
    while (~scanf("%d",&n)){  
		if (!n) break;
		if (ncase++) cout << endl;
		len = 0;
		for (i=0;i<n;i++){
			scanf("%s",s);	
			for (j=0;s[j];j++){
				str[len] = s[j] + 200;
				zone[len] = i;
				len++;
			}
			if (i==n-1){
				str[len] = 0;
			}
			else {
				zone[len] = i;
				str[len++] = 1+i;
			}
		}
		//# void da(char str[],int sa[],int rrank[],int height[],int n,int m){  
		da(str,sa,rrank,height,len,500);
		int l = 0,r = len+1;
		while (l < r-1){
			int mid = l+r>>1;
			if (isok(mid)){
				l = mid;
			}else {
				r = mid;
			}
		}
		//# cout << "l = " << l << endl;
		//# Debug(len);
		if (l==0){
			cout << "?" << endl;
		}else {
			memset(vis,0,sizeof(vis));
			while (!que.empty()) que.pop();
			que.push(zone[sa[1]]);
			vis[zone[sa[1]]] = 1;
			for (i=1;i<=len;i++){
				if (height[i]>=l){
					if (vis[zone[sa[i]]]==0){
						que.push(zone[sa[i]]);
						vis[zone[sa[i]]] = 1;
					}
				}else {
					if (que.size()>n/2){
						for (j=sa[i-1];j<sa[i-1]+l;j++){
							cout << char(str[j]-200);
						}
						cout << endl;
					}
					while (!que.empty()){
						vis[que.front()] = 0;	
						que.pop();
					}
					que.push(zone[sa[i]]);
					vis[zone[sa[i]]] = 1;
				}
			}
			if (que.size()>n/2){
				for (j=sa[i-1];j<sa[i-1]+l;j++){
					cout << char(str[j]-200);
				}
				cout << endl;
			}
		}
	}
    return 0;  
}





第二种思路

/***************************************************************** 
  > File Name: Cpp_Acm.cpp 
  > Author: Uncle_Sugar 
  > Mail: uncle_sugar@qq.com 
  > Created Time: 2016年08月01日 星期一 18时50分27秒 
 *****************************************************************/  
# include <cstdio>  
# include <cstring>  
# include <cctype>  
# include <cmath>  
# include <cstdlib>  
# include <climits>  
# include <iostream>  
# include <iomanip>  
# include <set>  
# include <map>  
# include <vector>  
# include <stack>  
# include <queue>  
# include <algorithm>  
using namespace std;  

# define rep(i,a,b) for (i=a;i<=b;i++)  
# define rrep(i,a,b) for (i=b;i>=a;i--)  

template<class T>void PrintArray(T* first,T* last,char delim=' '){   
	for (;first!=last;first++) cout << *first << (first+1==last?'\n':delim);   
}  

const int debug = 1;  
const int size  = 1000 + 300000 ;   
const int INF = INT_MAX>>1;  
typedef long long ll;  

const int MAXN = 500000 + 1000;    
#define F(x) ((x)/3+((x)%3==1?0:tb))    
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)    
int wa[MAXN*3],wb[MAXN*3],wv[MAXN*3],wss[MAXN*3];    
int c0(int *r,int a,int b)    
{    
	return r[a] == r[b] && r[a+1] == r[b+1] && r[a+2] == r[b+2];    
}    
int c12(int k,int *r,int a,int b)    
{    
	if(k == 2)    
		return r[a] < r[b] || ( r[a] == r[b] && c12(1,r,a+1,b+1) );    
	else return r[a] < r[b] || ( r[a] == r[b] && wv[a+1] < wv[b+1] );    
}    
void sort(int *r,int *a,int *b,int n,int m)    
{    
	int i;    
	for(i = 0;i < n;i++)wv[i] = r[a[i]];    
	for(i = 0;i < m;i++)wss[i] = 0;    
	for(i = 0;i < n;i++)wss[wv[i]]++;    
	for(i = 1;i < m;i++)wss[i] += wss[i-1];    
	for(i = n-1;i >= 0;i--)    
		b[--wss[wv[i]]] = a[i];    
}    
void dc3(int *r,int *sa,int n,int m)    
{    
	int i, j, *rn = r + n;    
	int *san = sa + n, ta = 0, tb = (n+1)/3, tbc = 0, p;    
	r[n] = r[n+1] = 0;    
	for(i = 0;i < n;i++)if(i %3 != 0)wa[tbc++] = i;    
	sort(r + 2, wa, wb, tbc, m);    
	sort(r + 1, wb, wa, tbc, m);    
	sort(r, wa, wb, tbc, m);    
	for(p = 1, rn[F(wb[0])] = 0, i = 1;i < tbc;i++)    
		rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p - 1 : p++;    
	if(p < tbc)dc3(rn,san,tbc,p);    
	else for(i = 0;i < tbc;i++)san[rn[i]] = i;    
	for(i = 0;i < tbc;i++) if(san[i] < tb)wb[ta++] = san[i] * 3;    
	if(n % 3 == 1)wb[ta++] = n - 1;    
	sort(r, wb, wa, ta, m);    
	for(i = 0;i < tbc;i++)wv[wb[i] = G(san[i])] = i;    
	for(i = 0, j = 0, p = 0;i < ta && j < tbc;p++)    
		sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++];    
	for(;i < ta;p++)sa[p] = wa[i++];    
	for(;j < tbc;p++)sa[p] = wb[j++];    
}    
//str和sa也要三倍    
void da(int str[],int sa[],int rank[],int height[],int n,int m)    
{    
	for(int i = n;i < n*3;i++)    
		str[i] = 0;    
	dc3(str, sa, n+1, m);    
	int i,j,k = 0;    
	for(i = 0;i <= n;i++)rank[sa[i]] = i;    
	for(i = 0;i < n; i++)    
	{    
		if(k) k--;    
		j = sa[rank[i]-1];    
		while(str[i+k] == str[j+k]) k++;    
		height[rank[i]] = k;    
	}    
}    
int sa[size],rrank[size],height[size];    

int n,k;        

int str[size],len;   
int zone[size];  
char s[size];  

int vis[200];  
set<int> st;

void Debug(int n){  
	for (int i=1;i<=n;i++){  
		cout << "*" << i << "*\t" << height[i] << "\t" << zone[sa[i]] << '\t';  
		PrintArray(str+sa[i],str+n,'\t');  
	}  
}  

struct Comper{  
	int operator () (const int x,const int y){  
		if (height[x]==height[y])
			return x<y?y:x;
		return height[x] < height[y]?x:y;  
	}  
}comp;  
/* 
 * 这种情况下会返回最小值的下标 
 */  

const int MAXRMQSIZE = 110000;  

struct RMQ{  
	int dp[MAXRMQSIZE][25];  
	int mm[MAXRMQSIZE];  
	//初始化RMQ, b数组下标从1开始,从0开始简单修改  
	RMQ(){}  
	void initRMQ(int n){  
		mm[0] = -1;  
		for(int i = 1; i <= n;i++){  
			mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];  
			dp[i][0] = i;  
		}  
		for(int j = 1; j <= mm[n];j++)  
			for(int i = 1;i + (1<<j) -1 <= n;i++)  
				dp[i][j] = comp(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);  
	}  
	//查询最大值  
	int rmq(int x,int y){  
		if (x > y)
			swap(x,y);
		int k = mm[y-x+1];  
		return comp(dp[x][k],dp[y-(1<<k)+1][k]);  
	}  
};  
RMQ rmqq;

int ans = 0;
vector<int> anspos;
int main()    
{    
	int i,j;    
	int ncase = 0;  
	while (~scanf("%d",&n)){    
		if (!n) break;  
		if (ncase++) cout << endl;  
		len = 0;  
		for (i=0;i<n;i++){  
			scanf("%s",s);    
			for (j=0;s[j];j++){  
				str[len] = s[j] + 200;  
				zone[len] = i;  
				len++;  
			}  
			if (i==n-1){  
				str[len] = 0;  
			}  
			else {  
				zone[len] = i;  
				str[len++] = 1+i;  
			}  
		}  
		//# void da(char str[],int sa[],int rrank[],int height[],int n,int m){    
		da(str,sa,rrank,height,len,500);  
		//# Debug(len);  
		int left,right;
		st.clear();
		anspos.clear();
		memset(vis,0,sizeof(vis));
		rmqq.initRMQ(len);
		ans = 0;
		for (left=right=1;left<=len;left++){
			while (st.size() <= n/2 && right<=len){
				if (vis[zone[sa[right]]]++==0){
					st.insert(zone[sa[right]]);	
				}
				right++;
			}
			if (st.size() <= n/2) break;
			//# cout << "left " << left << " right " << right ;
			int k = rmqq.rmq(left+1,right-1);
			//# cout << "left + 1 " << left+1 << " right-1 " << right-1 << " " << height[k]<< endl;
			if (height[k] > ans){
				ans = height[k];
				anspos.clear();
				anspos.push_back(k);
			}else if (height[k] == ans){
				if (anspos.empty()||height[rmqq.rmq(anspos.back(),k)] < ans)
					anspos.push_back(k);
			}
			
			if (--vis[zone[sa[left]]]==0){
				st.erase(zone[sa[left]]);
			}
		}
		if (ans==0){
			putchar('?');
			putchar('\n');
		}
		else{
			
			for (i=0;i<anspos.size();i++){
				int loc = sa[anspos[i]];
				for (j=loc;j<loc+ans;j++){
					putchar(char(str[j] - 200));
				}
				putchar('\n');
			}
		}
	}
	return 0;    
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值