A - Palindrome HDU - 6230[马拉车+bit]

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_38081836/article/details/83419114

题意:给出一个字符串,询问有多少个双回文(形如-----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;
}

猜你喜欢

转载自blog.csdn.net/m0_38081836/article/details/83419114