1. 程式人生 > >A - Palindrome HDU - 6230[馬拉車+bit]

A - Palindrome HDU - 6230[馬拉車+bit]

題意:給出一個字串,詢問有多少個雙迴文(形如-----i-----j-----)i,j為對稱中心。


題解:可以使用馬拉車演算法預處理出每個字元為對稱中心的迴文串長度,然後通過樹狀陣列維護下面的關係

  1. i < j i < j
  2. j r ( j ) < =
    i j - r(j) <= i
  3. i + r ( i
    ) > = j i + r(i) >= j

首先補充一些關於馬拉車的一些性質:

  1. 原陣列與轉換之後的陣列位置的對應為 p o s > 2 ( p o s + 1 ) pos -> 2*(pos + 1)
  2. p[i - 1]表示以i為中心的迴文串長度
  3. p[i]/2表示以i為中心的迴文半徑

我們可以通過遍歷字串的p陣列來得到以它為中心向左可以最長延伸到哪也就是第二個條件,第一個條件在遍歷更新bit的過程中已經滿足,接下來就是利用bit查詢能夠延伸到右邊的有多少個,然後相加即為結果。


收穫:

  1. 樹狀陣列竟然可以維護不等式關係!
  2. 馬拉車性質的理解

a c   c o d e ac\ code

/****陣列大小****/

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define debug cerr << "*" << endl;
#define rep(i, a, b) for(int i = a; i <= b; i++)
#define pre(i, a, b) for(int i = a; i >= b; i--)
#define met(a, b) memset(a, b, sizeof(a))
const int maxn = 1e6 + 10;
const int inf = 0x3f3f3f3f;

char s[maxn << 1], tmp[maxn << 1];
ll p[maxn << 1];
void init(char *s) {
    int len = strlen(s);
    tmp[0] = '@';
    tmp[1] = '#';
    int j = 2;
    for(int i = 0; i < len; i++) {
        tmp[j++] = s[i];
        tmp[j++] = '#';
    }
    tmp[j++] = '\0';
}

int manacher(char *s) {
    ll maxLen = 1;
    ll id = 0, mx = 0;
    ll len = strlen(s);
    for(int i = 0; i < len; i++) {
        if(i < mx) p[i] = min(p[2 * id - i], mx - i);
        else p[i] = 1;
        while(s[i + p[i]] == s[i - p[i]]) {
            p[i]++;
        }
        if(i + p[i] > mx) {
            mx = i + p[i];
            id = i;
        }
        maxLen = max(maxLen, p[i] - 1);
    }
    return maxLen;
}

ll c[maxn << 1];

ll lowbit(ll x) {
    return x & (-x);
}

void upd(ll pos, ll x) {
    while(pos < maxn) {
        c[pos] += x;
        pos += lowbit(pos);
        //cout << pos <<endl;
    }
}

ll query(ll pos) {
    ll res = 0;
    while(pos > 0) {
        res += c[pos];
        pos -= lowbit(pos);
    }
    return res;
}
vector<ll> g[maxn];
ll pp[maxn];
int main() {
    //cerr << "hqx is the best man!!" << endl;
    int T;
    scanf("%d", &T);
    while(T--) {
        met(c, 0);
        met(p, 0);
        scanf("%s", s);
        init(s);
        manacher(tmp);
        ll len = strlen(tmp);
        for(int i = 0; i < maxn; i++) g[i].clear();
        int k = 1;
        for(int i = 2; i < len; i += 2) {
            pp[k] = p[i] / 2 - 1;
            g[k - pp[k]].push_back(k);
            k++;
        }
        len = strlen(s);
        ll ans = 0;
        rep(i, 1, len) {
            rep(j, 0, (int)g[i].size() - 1) {
                upd(g[i][j], 1);
            }
            ans += query(min(pp[i] + i, len)) - query(i);
            //cerr << ans << endl;
        }
        printf("%lld\n", ans);
    }
    return 0;
}