您的位置:首页 > 其它

POJ 3261 字符串上的k次覆盖问题

2015-04-03 02:16 211 查看
题目大意:

给定一个数组,求一个最大的长度的子串至少出现过k次

一个子串出现多次,也就是说必然存在2个子串间的前缀长度为所求的值

通过二分答案,通过线性扫一遍,去判断出现次数,也就是说每次遇见一个height[i] , 出现次数就加1,否则重置为1

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 20010;
int rank
, sa
, height
;
int wa
, wb
, wsf
, wv
;
int a
;

int cmp(int *r , int a , int b , int l)
{
return r[a]==r[b] && r[a+l]==r[b+l];
}

void getSa(int *r , int *sa , int n , int m)
{
int i,j,p;
int *x=wa , *y=wb , *t;
for(i=0 ; i<m ; i++) wsf[i]=0;
for(i=0 ; i<n ; i++) wsf[x[i]=r[i]]++;
for(i=1 ; i<m ; i++) wsf[i] += wsf[i-1];
for(i=n-1 ; i>=0 ; i--) sa[--wsf[x[i]]]=i;

p=1;
for(j=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++) wsf[i]=0;
for(i=0 ; i<n ; i++) wsf[wv[i]]++;
for(i=1 ; i<m ; i++) wsf[i]+=wsf[i-1];
for(i=n-1 ; i>=0 ; i--) sa[--wsf[wv[i]]]=y[i];

t=x,x=y,y=t;
x[sa[0]]=0;
for(p=1 , i=1 ; i<n ; i++)
x[sa[i]] = cmp(y , sa[i-1] , sa[i] , j)?p-1:p++;
}
return ;
}

void getHeight(int *r , int *sa , int n)
{
for(int i=1 ; i<=n ; i++) rank[sa[i]]=i;
int k=0;
int j;
for(int 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 k)
{
int cnt=1;
for(int i=1 ; i<=n ; i++){
if(height[i]>=m){
cnt++;
//   cout<<"here: "<<m<<" "<<sa[i]<<" "<<sa[i-1]<<endl;
if(cnt>=k) return true;
}
else {cnt=1;if(cnt>=k) return true;}
}
return false;
}

int main()
{
//  freopen("a.in" , "r" , stdin);
int n,k;
while(~scanf("%d%d" , &n , &k))
{
int maxn =0 ;
for(int i=0 ; i<n ; i++){
scanf("%d" , a+i);
a[i]++;
maxn = max(maxn , a[i]);
}
a
=0;
getSa(a , sa , n+1 , maxn+1);
getHeight(a , sa , n);

int l=0 , r=n , ans=0;
while(l <= r){
int m=(l+r)>>1;
if(check(m,n,k)){
ans = m;
l=m+1;
}else r=m-1;
}
printf("%d\n" , ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: