[2019牛客多校训练第6场]Palindrome Mouse

链接:https://ac.nowcoder.com/acm/contest/886/C
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
分数:2800

题目描述
Doctor has a string s s s consisting of only lowercase letters. Doctor has got the set of all palindromic substrings of a string s s s, denoted by the set S S S. Now, he wants to choose two distinct strings a a a and b b b from the set S S S which satisfy that the string a is a a a substring of the string b b b. How many different pairs ( a a a, b b b) can Doctor choose?
输入描述:

There are multiple test cases. The first line contains an integer T ( 1 ≤ T ≤ 5 ) T(1 \leq T \leq 5) T(1T5), indicating the number of test cases. Test cases are given in the following.

Each test case consists of only one line, containing a non-empty string s s s ( 1 ≤ ∣ s ∣ ≤ 100000 1 \leq |s| \leq 100000 1s100000), consisting of only lowercase letters.

输出描述:

For each test case, output “Case #x: y” in one line (without quotes), where x indicates the case number starting from 1, and y denotes the answer to this test case.

示例1
输入

4
aaaa
abba
abacaba
abc

输出

Case #1: 6
Case #2: 4
Case #3: 14
Case #4: 0

题意:
给定一个字符串 s s s,设其所有本质不同的回文子串组成的集合为 S S S,问有多少对 ( a , b ) (a,b) (a,b)满足 ( a , b ∈ S ) (a,b \in S) (a,bS) a a a b b b的子串

题解:
果然对回文自动机的各个标签表示还是不够熟悉啊…
由于我们知道,如果 f a [ u ] = v fa[u]=v fa[u]=v那么 v v v就是 u u u的一个真子回文串。
我们从回文树的两个节点开始dfs。
那么我们对于每一个回文串 x x x统计所有合法的(长度大于等于1的) f a [ x ] fa[x] fa[x], f a [ f a [ x ] ] fa[fa[x]] fa[fa[x]], f a [ f a [ f a [ x ] ] ] . . . . . fa[fa[fa[x]]]..... fa[fa[fa[x]]].....的数量 c o [ x ] co[x] co[x]和他的所有后继节点的回文串数量 b o [ x ] bo[x] bo[x]
然后接下去进入下一个节点,进行相同的操作。
记住每个节点只能被统计一次,也只能被计算一次。
最后计算 ( ∑ b o [ i ] ∗ c o [ i ] ) − 本 质 不 同 回 文 串 总 数 (\sum bo[i]*co[i]) - 本质不同回文串总数 (bo[i]co[i]) 即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=400004;
const int D=27;
char s[MAXN];
int l;
struct PAM{
    int cnt,last;
    ll ans;
    int fa[MAXN],len[MAXN],ch[MAXN][D],co[MAXN],bo[MAXN],vis[MAXN];
    int create(int Len,int Fa){
        len[cnt]=Len;
        fa[cnt]=Fa;
        return cnt++;
    }
    void CLEAR(){
        memset(vis,-1,sizeof(vis));
        for(int i=0;i<cnt;i++){
            len[i]=0;fa[i]=0;
            memset(ch[i],0,sizeof(ch[i]));
        }
        last=0;cnt=0;
        create(0,1);
        create(-1,0);
        ans=0;
    }
    int getfail(int p,int n){
        for(;s[n-len[p]-1]!=s[n];p=fa[p]);
        return p;
    }
    int add(int c,int pos){
        int p=getfail(last,pos);
        if(!ch[p][c]){
            ch[p][c]=create(len[p]+2,ch[getfail(fa[p],pos)][c]);
        }
        last=ch[p][c];
        return last;
    }
    int dfs(int x){
        bo[x]=1;
        co[x]=0;
        for(int i=x;i>1;i=fa[i]){
            if(vis[i]!=-1)break;
            vis[i]=x;
            co[x]++;
        }
        for(int i=0;i<26;i++){
            if(ch[x][i]){
                bo[x]+=dfs(ch[x][i]);
            }
        }
        for(int i=x;i>1;i=fa[i]){
            if(vis[i]!=x)break;
            vis[i]=-1;
        }
        return bo[x];
    }
    ll getans(){
        ans=0;
        dfs(1);
        dfs(0);
        for(int i=2;i<cnt;i++){
            ans+=1LL*bo[i]*co[i];
        }
        return ans-cnt+2;
    }
}pam;
int w33ha(int CASE){
    scanf("%s",s+1);
    l=strlen(s+1);
    pam.CLEAR();
    for(int i=1;i<=l;i++){
        pam.add(s[i]-'a',i);
    }
    printf("Case #%d: %lld\n",CASE,pam.getans());
    return 0;
}
int main(){
    int T;scanf("%d",&T);
    for(int i=1;i<=T;i++)w33ha(i);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值