hdu 5814 Find the Period

询问子串的最小循环节

论文题:Efficient data structures for the factor periodicity problem.



#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
        
          #include 
          #include 
          
            #include 
           
             #include 
            
              using namespace std; #define N 200002 #define M 2000010 #define ULL unsigned long long #define LL long long #define ls (i << 1) #define rs (ls | 1) #define md ((ll + rr) >> 1) #define lson ll, md, ls #define rson md + 1, rr, rs #define inf 0x3f3f3f3f #define eps 1e-4 #define pii pair 
             
               #define MP make_pair #define mod 1000000007 char s[N]; int n; int sa[N], wa[N], wb[N], wv[N], wc[N]; int lg[N]; int lab[N][22]; int lab_cnt; struct Arith { int a, b, d; Arith(int a = -1, int d = -1, int b = -1) : a(a), d(d), b(b) {}; void init(int v) { a = b = v; d = -1; } void upd(int v) { if(a == -1) a = v; else if(d == -1) d = v - a; b = v; } int get_min(int p) { /* >= p */ if(a == -1) return inf; if(a >= p) return a; if(d == -1) return inf; if(b < p) return inf; int k = ceil((p-a+0.0) / d); return min(b, a + k * d); } int get_max(int p) { /* <= p */ if(a == -1) return -1; if(a > p) return -1; if(d == -1) return a; int k = (p-a) / d; return min(b, a + k * d); } Arith inv_cut(int val) {/* val - this */ if(a == -1) return *this; int t = a; a = val-b; b = val-t; return *this; } Arith add(int val) { /* val + this */ if(a == -1) return *this; a += val; b += val; return *this; } }; Arith merge2(Arith x, Arith y) { Arith ans; for(int i = x.a; i != -1 && x.a <= i && i <= x.b; i += x.d) { if(y.a <= i && i <= y.b && (y.d == -1 || (i-y.a) % y.d == 0)) ans.upd(i); } return ans; } Arith merge(Arith x, Arith y) { if(x.d == -1 || x.a + x.d == x.b) return merge2(x, y); else if(y.d == -1 || y.a + y.d == y.b) return merge2(y, x); else { if(x.d != y.d) return Arith(); if(x.a > y.a) swap(x, y); if(y.a > x.b) return Arith(); if((y.a-x.a)%x.d == 0) return Arith(y.a, min(y.b, x.b) == y.a ? -1 : x.d, min(y.b, x.b)); } return Arith(); } LL get_hx(int id, int j) { if(j < 0) return -1; return (LL)id * (n+1) + j; } struct Hash { const static int hxsz = 2333333; int fst[hxsz], nxt[N*22], e; LL state[N*22]; Arith val[N*22]; void init() { memset(fst, -1, sizeof fst); e = 0; } void insert(LL st, int v) { int u = st % hxsz; for(int i = fst[u]; ~i; i = nxt[i]) { if(state[i] == st) { val[i].upd(v); return ; } } state[e] = st; val[e].init(v); nxt[e] = fst[u]; fst[u] = e++; } Arith query(LL st) { if(st < 0) return Arith(); int u = st%hxsz; for(int i = fst[u];~i; i = nxt[i]) { if(state[i] == st) return val[i]; } return Arith(); } }hm; void init() { for(int i = 1, k = 0; i < N; i <<= 1, k++) lg[i] = k; hm.init(); lab_cnt = 0; } bool cmp(int *r, int a, int b, int l) { return r[a] == r[b] && r[a+l] == r[b+l]; } void da(char *r, int n, int m) { int i, j, k, p, *x = wa, *y = wb; for(i = 0; i < m; ++i) wc[i] = 0; for(i = 0; i < n; ++i) ++wc[x[i] = r[i]]; for(i = 1; i < m; ++i) wc[i] += wc[i-1]; for(i = n-1; i >= 0; --i) sa[--wc[x[i]]] = i; for(i = 0; i < n; ++i) { if(i == 0 || x[sa[i-1]] != x[sa[i]]) ++lab_cnt; lab[sa[i]][0] = lab_cnt; hm.insert(get_hx(lab_cnt, sa[i]), sa[i]); } for(j = 1, p = 1, k = 1; p < n; m = p, j <<= 1, k++) { for(i = n-j, p = 0; 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) wc[i] = 0; for(i = 0; i < n; ++i) ++wc[wv[i]]; for(i = 1; i < m; ++i) wc[i] += wc[i-1]; for(i = n-1; i >= 0; --i) sa[--wc[wv[i]]] = y[i]; swap(x, y); for(x[sa[0]] = 0, p = 1, i = 1; i < n; ++i) x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++; for(i = 0; i < n; ++i) { if(i == 0 || x[sa[i-1]] != x[sa[i]]) ++lab_cnt; lab[sa[i]][k] = lab_cnt; hm.insert(get_hx(lab_cnt, sa[i]/(j<<1)), sa[i]); } } for(; j <= n; j <<= 1, k++) for(i = 0; i < n; ++i) lab[i][k] = lab[i][k-1]; } int succ(int q, int p, int len) { int id = lab[p][lg[len]]; int k = q/len; Arith s1 = hm.query(get_hx(id, k)); Arith s2 = hm.query(get_hx(id, k+1)); int mi = min(s1.get_min(q), s2.get_min(q)); //printf("succ(%d, %d, %d) mi %d\n", q, p, len, mi); if(mi <= q + len) return mi; else return inf; } int pred(int q, int p, int len) { int id = lab[p][lg[len]]; int k = q/len; Arith s1 = hm.query(get_hx(id, k)); Arith s2 = hm.query(get_hx(id, k-1)); int mx = max(s1.get_max(q), s2.get_max(q)); //printf("pred(%d, %d, %d), mx %d\n", q, p, len, mx); if(mx >= q-len) return mx; return -1; } Arith occ(int p1, int len1, int p2, int len2) { //printf("occ [%d,%d], [%d,%d]\n", p1, p1+len1-1, p2, p2 + len2 -1); int p = succ(p2, p1, len1); int pos = p2 + len2 - 1 - len1 + 1; if(p > pos) return Arith(); int q = succ(p+1, p1,len1); if(q > pos) return Arith(p, -1, p); int d = q - p; int t = pred(pos, p1, len1); //printf("occ (%d,%d,%d)\n", p, d, t); puts(""); return Arith(p, d, t); } int largePS(int l, int r, int len) { if(len == 1) return s[l] == s[r] ? 1 : 0; int d = len >> 1; Arith s1 = occ(l, d, r-len+1, len).inv_cut(r+1); Arith s2 = occ(r-d+1, d, l, len).add(d-l); //printf("largePS(%d) s1(%d, %d, %d) s2(%d, %d, %d)\n", len,s1.a, s1.d, s1.b, s2.a, s2.d, s2.b); s1 = merge(s1,s2); //printf("merge (%d, %d, %d)\n", s1.a, s1.d, s1.b); puts(""); return s1.b; } int larger(int l, int r, int k) { if(k == 0) return 0; int d1 = succ(l+1, l, k); if(d1 == inf) return -1; d1 -= l; int d2 = pred(r-k, r-k+1, k); if(d2 == inf) return -1; d2 = r-d2+1 - k; //printf("larger(%d,%d,%d) d1 %d d2 %d\n", l, r,k,d1, d2); puts(""); return d1 == d2 ? r-l+1-d1 : -1; } int query(int l, int r) { int ans = 0; int i; for(i = 1; i < r-l+1; i <<= 1) { ans = max(ans, largePS(l, r, i)); //printf("ans %d %d\n", ans, i); } ans = max(ans, larger(l, r, i>>1)); return r-l+1 - ans; } int gao(int l, int r) { static char t[N]; static int fail[N]; int m = r - l + 1; for(int i = 0; i < m; ++i) t[i] = s[l+i]; fail[0] = -1; int i = 1, j = 0; while(i < m) { if(j < 0 || t[j] == t[i]) { ++j, ++i; fail[i] = j; } else j = fail[j]; } return m - fail[m]; } int getin() { char c; while((c=getchar()) && !('0' <= c && c <= '9')); int ans = c - '0'; while((c=getchar()) && '0' <= c&& c<= '9') ans = ans*10 + c-'0'; return ans; } int main() { int T; scanf("%d", &T); int cas = 1; while(T--) { init(); scanf("%s", s); n = strlen(s); da(s, n+1, 130); int m; m = getin(); printf("Case #%d:\n", cas++); while(m--) { int l, r; l = getin(); r = getin(); --l, --r; int ret = query(l, r); printf("%d\n", ret); } } } 
              
             
            
           
         
       
      
      
     
     
    
    
   
   

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值