Life Forms

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

题意:就是求n个串的中一个最大的子串,这个子串在超过n/2的串中出现。

题解:这是一道好题。首先一种解法就是用后缀数组来搞,首先把n个串拼接起来,然后,每个串后面加上一个特殊的额字符,然后求后缀数组以及h数组,然后一个很经典的做法就是二分长度,找到满足条件的长度,然后输出答案。这一题恶心了我一天。各种错误。1,统计的时候出错2是memset的数组开打了,结果T了,3是答案数组没有清空,结果wa了4特殊清空n==1时候没有考虑。printf(%s)是从起始位置输出字符直到遇到\0为止,合法,

 #include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=;
char str[maxn];
int id[maxn];
int wa[maxn],wb[maxn],wv[maxn],wn[maxn],a[maxn],sa[maxn];
int cmp(int* r,int a,int b,int l){
return r[a]==r[b]&&r[a+l]==r[b+l];
}
//n为字符串长度,m为字符的取值范围,r为字符串。后面的j为每次排序时子串的长度
void DA(int* r,int* sa,int n,int m){
int i,j,p,*x=wa,*y=wb,*t;
///对R中长度为1的子串进行基数排序
for(i=; i<m; i++)wn[i]=;
for(i=; i<n; i++)wn[x[i]=r[i]]++;
for(i=; i<m; i++)wn[i]+=wn[i-];
for(i=n-; i>=; i--)sa[--wn[x[i]]]=i;
for(j=,p=; p<n; j*=,m=p){
//利用了上一次基数排序的结果,对待排序的子串的第二关键字进行了一次高效地基数排序
for(p=,i=n-j; i<n; i++)y[p++]=i;
for(i=; i<n; i++)if(sa[i]>=j)y[p++]=sa[i]-j;
///基数排序
for(i=; i<n; i++)wv[i]=x[y[i]];
for(i=; i<m; i++)wn[i]=;
for(i=; i<n; i++)wn[wv[i]]++;
for(i=; i<m; i++)wn[i]+=wn[i-];
for(i=n-; i>=; i--)sa[--wn[wv[i]]]=y[i];
///当p=n的时候,说明所有串都已经排好序了
///在第一次排序以后,rank数组中的最大值小于p,所以让m=p
for(t=x,x=y,y=t,p=,x[sa[]]=,i=; i<n; i++)
x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
}
return;
}
///后缀数组 计算height数组
/**
height数组的值应该是从height[1]开始的,而且height[1]应该是等于0的。
原因是,+因为我们在字符串后面添加了一个0号字符,所以它必然是最小的
一个后缀。而字符串中的其他字符都应该是大于0的(前面有提到,使用倍
增算法前需要确保这点),所以排名第二的字符串和0号字符的公共前缀
(即height[1])应当为0.在调用calheight函数时,要注意height数组的范
围应该是[1..n]。所以调用时应该是calheight(r,sa,n)
而不是calheight(r,sa,n+1)。*/
int rank[maxn],height[maxn];
void calheight(int* r,int* sa,int n){
int i,j,k=;
for(i=; i<=n; i++)rank[sa[i]]=i;
for(i=; i<n; height[rank[i++]]=k)
for(k?k--:,j=sa[rank[i]-]; r[i+k]==r[j+k]; k++);
return;
}
int t;
char temp[];
bool vis[];
bool getsum(int len,int n){
memset(vis,,sizeof(vis));
int counts=;
for(int i=;i<=n;i++){
if(height[i]<len){
memset(vis,,sizeof(vis));
counts=;
}
else {
if(!vis[id[sa[i-]]]){
vis[id[sa[i-]]]=;counts++;
}
if(!vis[id[sa[i]]]){
vis[id[sa[i]]]=;counts++;
}
if(counts>t/){
return true;
}
}
}
return false;
}
char www[maxn];
void print(int len,int n){
memset(vis,,sizeof(vis));
int counts=,tag=;
for(int i=;i<=n;i++){
if(height[i]<len){
memset(vis,,sizeof(vis));
counts=;
tag=;
}
else {
if(!vis[id[sa[i-]]]){
vis[id[sa[i-]]]=;counts++;
}
if(!vis[id[sa[i]]]){
vis[id[sa[i]]]=;counts++;
}
if(counts>t/&&!tag){
tag=;
for(int j=;j<len;j++){
www[j]=a[sa[i]+j]-+'a';
}
www[len]='\0';//这里由于自己没有加上这一句,结果wa了,因为www之前没有清空
printf("%s\n",www);
}
}
} }
char temp2[];
int main(){
int sg=;
while(~scanf("%d",&t)&&t){
if(sg>)puts("");
sg=;
memset(temp2,,sizeof(temp2));
int sumlen=,tp=,r=;
for(int i=;i<=t;i++){
memset(temp,,sizeof(temp));
scanf("%s",temp);
if(i==)
strcpy(temp2,temp);
int len=strlen(temp);
r=max(r,len);
for(int j=;j<len;j++){
a[sumlen+j]=temp[j]-'a'+;
id[sumlen+j]=i;
}
sumlen+=len;
a[sumlen]=tp++;
id[sumlen++]=i;
}
id[sumlen]=t;
DA(a,sa,sumlen+,);
calheight(a,sa,sumlen);
int ans=,l=;
while(l<=r){
int mid=(l+r)/;
if(getsum(mid,sumlen)){
l=mid+;
ans=mid;
}
else{
r=mid-;
}
}
if(ans==)printf("?\n");
else{
if(t==)printf("%s\n",temp2);
else
print(ans,sumlen);
} }
return ;
}
上一篇:AOP 应用 性能


下一篇:[SoapUI] 在SoapUI里获取Excel中多行数据并存入List