回文(manacher +フェンウィック木)

タイトル

文字列のようなアリス、特に長い文字列。各文字列のために、彼女は文字列がどのようにエレガントに判断するために、特別な評価システムを持っています。彼女は、文字列S [1ことを定義します。.3n-2](≧2)が一及び半パリンドローム場合とされている場合にのみ、それを満たすS [I] = S [2N-1] = S [2N + I-2](1≤i≤n)たとえば.FOR、abcbabcは1-と半パリンドローム文字列であり、かつabccbaabc
ではありません。さて、アリスはいくつかの長い文字列を生成しました。彼女は1-と半パリンドロームであるどのように多くのサブストリングを見つけるためにあなたの助けを求めます。
入力は、
最初の行は、テストケースの数です。各テストケースのために、文字列を含む唯一のラインは、(文字列の長さ未満または500000に等しいがある
)、この文字列は、小文字から成ります。
出力
各テストケースのために、一及び半パリンドロームサブストリングの数を供与出力整数。
サンプル入力

1
ababcbabccbaabc

サンプル出力

2

ヒント

例えば、入力は、一と半パリンドロームストリング二つのストリングがあり、 a b a b ABAB a b c b a b c abcbabc

説明

S理由[1 .3n-2] (≧2)、S [I] = S [2N-1] = S [2N + I-2](1≤i≤n)は、 1〜2 N-を得ることができます図1は、パリンドローム配列であり、この配列は奇数であり、対称の中心は、Nです。さらに与えるN〜3N-2パリンドローム配列が奇数、2N-1の対称の中心であることができます。これらの条件を満たすために、それは与えられた文字列内の2つのセンターを見つけることです。
検索文字列の結果は、条件がパリンドローム配列が奇数(チューブがそうもシリーズ)で必要なので、私を設定し、jは、さらに説明します。したがって、manacherアルゴリズムを使用し、最初の文字列の成長lenの配列を見つけ、その後、私は(中心点もカウント)パリンドローム半径の中心で表されるLEN [I](偶数系列および休暇)文字列を更新します。
次に列挙前記iは、答えを求めること[I、I + lenの[Iであり、各中央パリンドローム ] -1] 、J数、j∈[I、I + lenの[I] -1] そして、J-lenの[J]≤i。
例えばcbcbcbcため、結果は2つのcbcb二BCBC、cbcbcbcを含む、5です。リクエスト長3N-2の主題ので、これだけ4,7,10-等。我々は2つのだけのパリンドロームの中心を気にし、気にしない、私jは権利の範囲内である。しかし、一番左のjが未満か、私に等しいです。(私の正しい選択され、jは、実際には、物品の列の長さは3 *(J-I + 1 )-2、I jのパッケージは、中央に来るI、中心とjとパリンドロームであることができます長さに等しいより大きくなければならない3 *(J-I + 1 )-2、 質問の選択は、3 *(jは-I + 1求めて )-2)
vectoによるメモリアレイに、我々は1〜レンズjから残っている添え字をJ。それから私は、1〜I-1 jは達することができる1〜レンズは私のツリーアレイの選択に既に存在している]を選択し、我々はちょうどのような私の右の右の境界に番号jの内容を検索します。次いでANS + =クエリが(MIN(レンズ 、iがlenの+ [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