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

[BZOJ2534] L-gap字符串

时间:2018-03-31 20:38:57      阅读:131      评论:0      收藏:0      [点我收藏+]

标签:nlogn   最长公共前缀   字符串   inline   read   正整数   代码   hint   str   

Description

有一种形如uvu形式的字符串,其中u是非空字符串,且V的长度正好为L,那么称这个字符串为L-Gap字符串 
给出一个字符串S,以及一个正整数L,问S中有多少个L-Gap子串. 

 

Input

第一行一个数字L 
第二行一个字符串S 

 

Output

一个数字表示S中有多少个L-Gap子串. 

 

Sample Input

3
aabbaa

Sample Output

2

HINT

S的长度不超过50000,L<=10

 

解题思路:

考虑枚举u串的长度k,那么当前枚举到的L-gap串的长度就是2 * k + L,然后把整个字符串分成若干个长度为2 * k + L的块,对于每一个块算在u串能取的区间是多少,对于块中两个u串的开始下标l1, l2,可以求出包括自身的情况下向左可以移动的长度Min(前缀l1,l2的最长公共后缀, len),向右可以移动的长度Min(后缀l1,l2的最长公共前缀,len),二分+hash搞一下就可以了,如果说可以移动的总长度>= k,显然这个块就会产生 k - 总长度 + 1种u串,然后对于每一个k,所划分出的每一个块去算,总复杂度是(nlogn^2)

技术分享图片
/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define N (100005)
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
template <class T>
inline void read(T &x){
    int f = 0, ch = 0; x = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == -) f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 0;
    if(f) x = -x;
}
const ull base = 233;
char s[N]; 
int n, m, ans;
ull pw[N], hs[N];
inline ull get(int l, int r){
    if(l > r) return 0; return hs[r] - hs[l-1] * pw[r-l+1];
}
inline int getpre(int x, int y, int lim){
    int l = 0, r = lim, ans = 0;
    while(l <= r){
        int mid = l + r >> 1;
        if(get(x - mid + 1, x) == get(y - mid + 1, y))
            ans = mid, l = mid + 1; else r = mid - 1;
    }
    return ans;
}
inline int getsuf(int x, int y, int lim){
    int l = 0, r = lim, ans = 0;
    while(l <= r){
        int mid = l + r >> 1;
        if(get(x, x + mid - 1) == get(y, y + mid - 1))
            ans = mid, l = mid + 1; else r = mid - 1;
    }
    return ans;
}
inline void solve(int L, int R){
    int len = (R - L + 1 - m) / 2, l1 = L, l2 = R - len + 1;
    int llen = getpre(l1, l2, len), rlen = getsuf(l1, l2, len);
    int now = (llen && rlen) ? llen + rlen - 1 : llen + rlen;
    if(now >= len) ans += now - len + 1;
}
int main(){
    pw[0] = 1, read(m);
    scanf("%s", s + 1); int n = strlen(s + 1);
    for(int i = 1; i < N; i++) pw[i] = pw[i-1] * base;
    for(int i = 1; i <= n; i++) hs[i] = hs[i-1] * base + s[i];
    for(int k = 1; k <= (n - m) / 2; k++)
        for(int i = 1; i <= n; i += k) solve(i, i + 2 * k + m - 1);
    cout << ans;
    return 0;
}
萌萌哒的代码>.<

 

[BZOJ2534] L-gap字符串

标签:nlogn   最长公共前缀   字符串   inline   read   正整数   代码   hint   str   

原文地址:https://www.cnblogs.com/mangoyang/p/8683721.html

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