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

hdu 5008

时间:2014-09-15 14:10:49      阅读:202      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   io   os   ar   for   数据   

因为一看到有关子串就主动的联想后缀数组

 

所有后缀的前缀去重后就是所有子串(好像是废话)

这样就可以得到每个后缀的子串个数。

二分查找到第k个所在的位置。

在二分处理所有可以出现该串的sa区间。

最小就是维护sa数组。

 

bubuko.com,布布扣
  1 //rank从0开始
  2 //sa从1开始,因为最后一个字符(最小的)排在第0位
  3 //high从2开始,因为表示的是sa[i-1]和sa[i]
  4 #include <cstdio>
  5 #include <cstring>
  6 #include <iostream>
  7 #include <algorithm>
  8 #define root 1,n,1
  9 #define lson l,mid,rt<<1
 10 #define rson mid+1,r,rt<<1|1
 11 #define M 120010
 12 #define INF 10000007
 13 using namespace std;
 14 typedef long long LL;
 15 LL rank[M],sa[M],X[M],Y[M],high[M],init[M];
 16 LL buc[M];
 17 struct SegmentTree{
 18     LL Min[M << 2];
 19     void pushup(LL rt){
 20         Min[rt] = min(Min[rt<<1],Min[rt<<1|1]);
 21     }
 22     void build(LL l,LL r,LL rt){
 23         if(l == r){
 24             Min[rt] = sa[l];
 25             return;
 26         }
 27         LL mid = (l + r) >> 1;
 28         build(lson);
 29         build(rson);
 30         pushup(rt);
 31     }
 32     LL query(LL L,LL R,LL l,LL r,LL rt){
 33         if(L <= l && r <= R){
 34             return Min[rt];
 35         }
 36         LL mid = (l + r) >> 1;
 37         LL ans = INF;
 38         if(L <= mid) ans = min(query(L,R,lson),ans);
 39         if(mid + 1 <= R) ans = min(query(L,R,rson),ans);
 40         return ans;
 41     }
 42 };
 43 SegmentTree sgt;
 44 void calhigh(LL n) {
 45     LL i , j , k = 0;
 46     for(i = 1 ; i <= n ; i++) rank[sa[i]] = i;
 47     for(i = 0 ; i < n ; high[rank[i++]] = k)
 48         for(k?k--:0 , j = sa[rank[i]-1] ; init[i+k] == init[j+k] ; k++);
 49 }
 50 bool cmp(LL *r,LL a,LL b,LL l) {
 51     return (r[a] == r[b] && r[a+l] == r[b+l]);
 52 }
 53 void suffix(LL n,LL m = 128) {
 54     LL i , l , p , *x = X , *y = Y;
 55     for(i = 0 ; i < m ; i ++) buc[i] = 0;
 56     for(i = 0 ; i < n ; i ++) buc[ x[i] = init[i]  ] ++;
 57     for(i = 1 ; i < m ; i ++) buc[i] += buc[i-1];
 58     for(i = n - 1; i >= 0 ; i --) sa[ --buc[ x[i] ]] = i;
 59     for(l = 1,p = 1 ; p < n ; m = p , l *= 2) {
 60         p = 0;
 61         for(i = n-l ; i < n ; i ++) y[p++] = i;
 62         for(i = 0 ; i < n ; i ++) if(sa[i] >= l) y[p++] = sa[i] - l;
 63         for(i = 0 ; i < m ; i ++) buc[i] = 0;
 64         for(i = 0 ; i < n ; i ++) buc[ x[y[i]] ] ++;
 65         for(i = 1 ; i < m ; i ++) buc[i] += buc[i-1];
 66         for(i = n - 1; i >= 0 ; i --) sa[ --buc[ x[y[i]] ] ] = y[i];
 67         for(swap(x,y) , x[sa[0]] = 0 , i = 1 , p = 1 ; i < n ; i ++)
 68             x[ sa[i] ] = cmp(y,sa[i-1],sa[i],l) ? p-1 : p++;
 69     }
 70     calhigh(n-1);//后缀数组关键是求出high,所以求sa的时候顺便把rank和high求出来
 71 }
 72 
 73 
 74 //当需要反复询问两个后缀的最长公共前缀时用到RMQ
 75 LL Log[M];
 76 LL best[20][M];
 77 void initRMQ(LL n) {//初始化RMQ
 78     for(LL i = 1; i <= n ; i ++) best[0][i] = high[i];
 79     for(LL i = 1; i <= Log[n] ; i ++) {
 80         LL limit = n - (1<<i) + 1;
 81         for(LL j = 1; j <= limit ; j ++) {
 82             best[i][j] = min(best[i-1][j] , best[i-1][j+(1<<i>>1)]);
 83         }
 84     }
 85 }
 86 LL lcp(LL a,LL b) {//询问a,b后缀的最长公共前缀
 87     //a = rank[a];    b = rank[b];
 88     //if(a > b) swap(a,b);
 89     //a ++;
 90     if(a>b)return 0;
 91     LL t = Log[b - a + 1];
 92     return min(best[t][a] , best[t][b - (1<<t) + 1]);
 93 }
 94 
 95 char str[M];
 96 LL dlen[M];
 97 
 98 void getlen(LL n,LL len){
 99     //dlen[1]=len-sa[1];
100     for(LL i=1;i<=n;i++){
101         dlen[i]=len-sa[i]-high[i];
102         //printf("%d ",dlen[i]);
103     }
104     //cout<<endl;
105     for(LL i=1;i<=n;i++){
106         dlen[i]+=dlen[i-1];
107     }
108 }
109 void findK(LL n,LL k,LL &start,LL &len){
110     //printf("%I64d %I64d\n",k,dlen[n]);
111     if(k>dlen[n]||k<=0){
112         start=len=0;
113         return ;
114     }
115     LL l=1,r=n;
116     while(l<=r){
117         LL mid=(l+r)>>1;
118         if(dlen[mid]>=k) r=mid-1;
119         else l=mid+1;
120     }
121     start=l;
122     len=k-dlen[start-1]+high[start];
123     //printf("start:%I64d len:%I64d\n",start,len);
124 }
125 LL findLcp(LL start,LL len,LL n){
126     LL l=start + 1,r=n;
127     while(l<=r){
128         LL mid=(l+r)>>1;
129         if(lcp(start+1,mid)>=len)l=mid+1;
130         else r=mid-1;
131     }
132     //printf("start:%I64d r:%I64d\n",start,r);
133     return sgt.query(start,r,root);
134 }
135 int main() {
136     //预处理每个数字的Log值,常数优化,用于RMQ
137     LL l,r,q;
138     LL v,u;
139     LL start,llen;
140     Log[0] = -1;
141     for(LL i = 1; i < M ; i ++) {
142         Log[i] = (i&(i-1)) ? Log[i-1] : Log[i-1] + 1 ;
143     }
144     //*******************************************
145     //    n为数组长度,下标0开始
146     //    将初始数据,保存在init里,并且保证每个数字都比0大
147     //    m = max{ init[i] } + 1
148     //    一般情况下大多是字符操作,所以128足够了
149     //*******************************************
150 
151     while(scanf("%s",str)!=EOF){
152         l = r  = 0;
153         LL n=strlen(str);
154         for(LL i=0;i<n;i++)init[i]=str[i];
155         init[n]=0;
156         suffix(n+1);
157         initRMQ(n);
158         getlen(n,n);
159         sgt.build(root);
160         scanf("%I64d",&q);
161         for(LL i=1;i<=q;i++){
162             scanf("%I64d",&v);
163             u=(l^r^v)+1;
164             findK(n,u,start,llen);
165             //printf("u:%I64d\n",u);
166             if(llen==0&&start==0){
167                 l=0,r=0;
168                 printf("0 0\n");
169                 continue;
170             }
171             LL ans=findLcp(start,llen,n);
172             l=ans;r=ans+llen-1;
173             l++;r++;
174             printf("%I64d %I64d\n",l,r);
175         }
176     }
177 //    init[n] = 0;
178 //    suffix(n+1,m);
179 }
180 /*
181 acab
182 10
183 2
184 */
View Code

 

hdu 5008

标签:style   blog   http   color   io   os   ar   for   数据   

原文地址:http://www.cnblogs.com/youyouyou/p/3972623.html

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