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

题目大意:

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

 

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

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

 

 1 #include <cstdio>

 2 #include <cstring>

 3 #include <iostream>

 4 using namespace std;

 5 const int N = 20010;

 6 int rank[N] , sa[N] , height[N];

 7 int wa[N] , wb[N] , wsf[N] , wv[N];

 8 int a[N];

 9 

10 int cmp(int *r , int a , int b , int l)

11 {

12     return r[a]==r[b] && r[a+l]==r[b+l];

13 }

14 

15 void getSa(int *r , int *sa , int n , int m)

16 {

17     int i,j,p;

18     int *x=wa , *y=wb , *t;

19     for(i=0 ; i<m ; i++) wsf[i]=0;

20     for(i=0 ; i<n ; i++) wsf[x[i]=r[i]]++;

21     for(i=1 ; i<m ; i++) wsf[i] += wsf[i-1];

22     for(i=n-1 ; i>=0 ; i--) sa[--wsf[x[i]]]=i;

23 

24     p=1;

25     for(j=1 ; p<n ; j*=2 , m=p){

26         for(p=0 , i=n-j ; i<n ; i++) y[p++]=i;

27         for(i=0 ; i<n ; i++) if(sa[i]>=j) y[p++]=sa[i]-j;

28 

29         for(i=0 ; i<n ; i++) wv[i]=x[y[i]];

30         for(i=0 ; i<m ; i++) wsf[i]=0;

31         for(i=0 ; i<n ; i++) wsf[wv[i]]++;

32         for(i=1 ; i<m ; i++) wsf[i]+=wsf[i-1];

33         for(i=n-1 ; i>=0 ; i--) sa[--wsf[wv[i]]]=y[i];

34 

35         t=x,x=y,y=t;

36         x[sa[0]]=0;

37         for(p=1 , i=1 ; i<n ; i++)

38             x[sa[i]] = cmp(y , sa[i-1] , sa[i] , j)?p-1:p++;

39     }

40     return ;

41 }

42 

43 void getHeight(int *r , int *sa , int n)

44 {

45     for(int i=1 ; i<=n ; i++) rank[sa[i]]=i;

46     int k=0;

47     int j;

48     for(int i=0 ; i<n ; height[rank[i++]]=k)

49         for(k?k--:0 , j=sa[rank[i]-1] ; r[i+k]==r[j+k] ; k++);

50     return;

51 }

52 

53 bool check(int m , int n , int k)

54 {

55     int cnt=1;

56     for(int i=1 ; i<=n ; i++){

57         if(height[i]>=m){

58             cnt++;

59          //   cout<<"here: "<<m<<" "<<sa[i]<<" "<<sa[i-1]<<endl;

60             if(cnt>=k) return true;

61         }

62         else {cnt=1;if(cnt>=k) return true;}

63     }

64     return false;

65 }

66 

67 int main()

68 {

69   //  freopen("a.in" , "r" , stdin);

70     int n,k;

71     while(~scanf("%d%d" , &n , &k))

72     {

73         int maxn =0 ;

74         for(int i=0 ; i<n ; i++){

75             scanf("%d" , a+i);

76             a[i]++;

77             maxn = max(maxn , a[i]);

78         }

79         a[n]=0;

80         getSa(a , sa , n+1 , maxn+1);

81         getHeight(a , sa , n);

82 

83         int l=0 , r=n , ans=0;

84         while(l <= r){

85             int m=(l+r)>>1;

86             if(check(m,n,k)){

87                 ans = m;

88                 l=m+1;

89             }else r=m-1;

90         }

91         printf("%d\n" , ans);

92     }

93     return 0;

94 }

 

你可能感兴趣的:(字符串)