회문 (manacher + 펜윅 나무)

이름

문자열과 같은 앨리스, 특히 긴 문자열. 각 문자열의 경우, 그녀는 캐릭터가 얼마나 우아한 판단하는 특별한 평가 시스템을 가지고 있습니다. 그녀는 문자열 [1 S 것으로 정의한다. .3n -2- (n≥2)는 1과 반 팔린 드롬의 경우와있는 경우에만이를 만족 S [I] = S [2N-I] = S [2N + I-2] (1≤i≤n) 예 .FOR, abcbabc는 1과 반 회문 문자열이며 abccbaabc
아니다. 이제 앨리스는 약간 긴 문자열을 생성했습니다. 그녀는 1과 반 상동 인 얼마나 많은 문자열을 찾기 위해 당신의 도움을 부탁드립니다.
입력
첫 번째 라인은 테스트 케이스의 수이다. 테스트 케이스를 들어, 문자열을 포함하는 단 하나의 라인 (문자열의 길이보다 작거나 같 500,000있다
),이 문자열은 소문자로 구성된다.
산출
각 테스트 케이스를 들어, 1과 상동 하위 절반의 수를 기부 출력 정수.
샘플 입력

1
ababcbabccbaabc

샘플 출력

힌트

예시적인 입력에서 1과 반 회문 문자열 개의 하위있다, a b a b ABAB 하고 a b c b a b c abcbabc .

설명

S [1 .3n-2] 때문에 (n≥2), S (1≤i≤n), [I] = S [2N-I] = S [I-2 + 2N] 를 얻을 수 1 ~ 2N- 하나는 팔린 드롬 서열이며,이 서열은 대칭의 중심 N 홀수이다. 또한 수득 N ~ 3N -2- 팔린 드롬 서열은 홀수, 2N-1 대칭 중심있다. 이러한 조건을 충족하기 위해서는 주어진 문자열에있는 두 개의 센터를 찾는 것입니다.
검색 문자열의 결과, 조건 팔린 드롬 서열이 홀수 (튜브 이렇게 짝수 시리즈) 인 요구 때문에 설정 I, J, 상기 설명한다. 따라서 manacher 알고리즘을 사용하여, 먼저 캐릭터의 성장 렌 배열을 발견하고 난 (중심점도 카운트)를 회문 반경의 중심으로 표현되는 LEN [I] (짝수 시리즈 떠나) 스트링을 갱신 .
이어서, 상기 열거 나, 해답을 찾는 것은 [I, I + 렌 [I에서 각각 중앙 회문 ] -1] , j 번째의 수, j∈ [I, I + 렌 [I] -1] 그리고 J-렌 [J] ≤i.
cbcbcbc 예를 들어, 결과는 두 cbcb 두 BCBC하는 cbcbcbc를 포함하는, 5이다. 같은 단지 4,7,10- 요청 길이 3N-2의 주제, 이후. 그러나 우리는 우리가 두 상동 센터에 관심 상관 없어, 난 j는 권리의 범위 내에는이 J 미만의 대부분이 왼쪽 또는 내가 같음. (수정 난 중 하나를 선택, j는, 실제로, 문서의 문자열 길이가 3 * (j는-I + 1 ) -2, I , J 패키지 J 중심으로서, 중심에 난 와서 팔린 드롬이다 수 길이보다 크거나 같아야 3 * (j-I + 1 ) -2, 질문의 선택은 3 * (j는-I + 1 요구하므로 ) -2)
vecto하여 메모리 어레이에 우리는 1 ~ 렌즈 J에서 왼쪽 된 첨자 J. 그런 다음 1 ~ 렌즈 난을 선택, 1 ~ I-1 J 도달 할 수있는 것은 이미 난의 트리 배열 선택에 존재하는, 우리는 단지 내가 바로의 오른쪽 경계의 숫자 J의 내용을 찾을 수있다. 이어서 ANS + = 질의가 (분 (렌즈 , I 렌 + [I] -1)) - 질의 (I) 내가 할 경우 문제를 만족하는 것은 아니다 I I에게 ==의 J 대표를 포함하고 있다면 때문에 포함되지 않은 경우 주 일반 회문의 문자열로.
펜윅 나무가있는 역할은 빠르게 쿼리 범위와 속도이다.

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define maxn 500005
#define ll long long
using namespace std;
ll c[maxn];
int lowbit(int x){
    return x&(-x);
}
void updata(int x, int y, int n){
    int i;
    for(i = x; i <= n; i += lowbit(i))
        c[i] += y;
}
ll query(int x){
    int i;
    ll ans = 0;
    for(i = x; i; i -= lowbit(i))
        ans += c[i];
    return ans;
}
char s[maxn], str[maxn*2];
int lens;
void inint(char *s){
    int i;
    str[0] ='@';
    for(i = 1; i <= lens*2; i += 2){
        str[i] ='#';
        str[i+1] =s[i/2];
    }
    str[2*lens+1] = '#';
    str[2*lens+2] = '$';
}
int len[500005*2];
void manacher(int n){
    int i, po = 0, mx = 0;
    for(i = 1; i <= n; i++){
        if(mx > i)
            len[i] = min(mx-i, len[2*po-i]);
        else
            len[i] = 1;
        while(str[i-len[i]] == str[i+len[i]])
            len[i]++;
        if(i+len[i] > mx){
            mx = i+len[i];
            po = i;
        }
    }
}
vector<int> a[500005];
int main(){
    int t, i, j;

    scanf("%d", &t);
    while(t--){
        ll ans = 0;
        scanf("%s", s);
        memset(c, 0, sizeof(c));
        lens = strlen(s);
        inint(s);
        manacher(lens*2+1);
        for(i = 2; i <= lens*2; i += 2) len[i/2] = len[i]/2;
        for(i = 1; i <= lens; i++) a[i].clear();
        for(i = 1; i <= lens; i++) a[i-len[i]+1].push_back(i);
        for(i = 1; i <= lens; i++){
            for(j = 0; j < a[i].size(); j++)
                updata(a[i][j], 1 , lens);
            ans += query(min(lens, i+len[i]-1)) - query(i);
        }
        printf("%lld\n", ans);
    }

    return 0;
}
发布了52 篇原创文章 · 获赞 2 · 访问量 895

추천

출처blog.csdn.net/qq_44714572/article/details/97617877