刚开始是听说了要用manacher采取写的,但是不难看出要使用manacher,因为题目要求的1个半回文串,其实就是两个回文中心的交集,你要找两个回文中心,让它们的回文半径可以互相覆盖即可。问题转化成了对于一个回文中心,它覆盖的左侧的所有回文中心中( 向右覆盖的范围超过i )这样的点的数量。这样就变成了求区间中大于x的数的个数,可以用主席树解决。

#include<iostream>
#include<cstring>
#include <string>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e6+20;
const int maxm=2e7+20;
char s[maxn],s_new[maxn];
int p[maxn];
int init()
{
    int len=(int)strlen(s);
    s_new[0]='$';
    s_new[1]='#';
    int j=2;
    for(int i=0;i<len;i++)
    {
        s_new[j++]=s[i];
        s_new[j++]='#';
    }
    s_new[j]=0;
    return j;
}
int manacher()
{
    int len=init();
    int id=0,mx=0;
    for(int i=1;i<len;i++)
    {
        if(i<mx)
            p[i]=min(p[2*id-i],mx-i);
        else
            p[i]=1;
        while(s_new[i-p[i]]==s_new[i+p[i]])
            p[i]++;
        if(mx<i+p[i])
        {
            id=i;
            mx=i+p[i];
        }
    }
    return len;
}
int n,m,cnt;
int tree[maxn],ls[maxm],rs[maxm],sum[maxm];
void update(int k,int pre,int &now,int l,int r){
    now=++cnt;
    ls[now]=ls[pre];
    rs[now]=rs[pre];
    sum[now]=sum[pre]+1;

    if(l==r){
        return;
    }
    int m=(l+r)>>1;
    if(k<=m) update(k,ls[pre],ls[now],l,m);
    else update(k,rs[pre],rs[now],m+1,r);
}
int query(int a,int b,int l,int r,int L,int R){
    if(L<=l&&r<=R){
        return sum[b]-sum[a];
    }
    int ans=0;
    int mid=(l+r)>>1;
    if(mid>=L)
        ans+=query(ls[a], ls[b], l, mid, L, R);
    if(mid<R)
        ans+=query(rs[a], rs[b], mid+1, r, L, R);
    return ans;
}
int main()
{
    int T;
    cin>>T;
    while(T--){
        cnt=0;
        tree[0]=ls[0]=rs[0]=sum[0]=0;
        scanf("%s",s);
        int len=manacher();
        m=len/2;
        ll ans=0;
        for(int i=1;i<m;i++)
        {
            int L=i-p[i*2]/2+1;
            if(L!=i)
                update(L,tree[i-1],tree[i],1,m);
            else
                tree[i]=tree[i-1];
        }

        for(int i=1;i<m;i++){
            int R=i+p[i*2]/2-1;
            int t=query(tree[i], tree[R], 1, m, 1, i);
            ans+=t;
        }

        printf("%lld\n",ans);
    }
}

  但是我的板子一直过不了,一直TLE,借用了以为其他人的主席树板子才能过,好迷啊。

  借用模版:https://blog.csdn.net/know_heng/article/details/78590061

  待更新:树状数组离线做法

02-13 14:52