• UESTC OJ 1999(回文树)


     

    传送门

    题面:

    也许这是唯一能阻止乐爷AK的方法( Just for Fun )

    Time Limit: 1500 MS     Memory Limit: 512 MB

    Submit Status

    一个字符串如果从前往后读和从后往前读是一样的,那么它被称为回文串。举个例子,"a","aa","appa","queryreuq"都是回文串。

    对于一个初始为空的字符串S,你可以进行以下两种操作:

    1.在S的末尾加一个小写字母。

    2.移除S的最后一个字母。

    每进行完一个操作,你需要统计S中回文串的数量。对于字符串S和整数i,j(1<=i<=j<=|S|),S[i,j]代表S中第i个字符到第j个字符构成的子串。你需要输出满足S[i,j]是回文串的(i,j)对数。

    Input

    输入包含两行。

    第一行,QQ,给出操作的次数。

    第二行,操作以一个长度为QQ的字符串给出,第i个字符Ki表示第ii次操作。

    Ki是−’或者小写英语字母('a','b',...'z')(不包括括号)。

    如果字符是‘−’,你应该移除S的最后一个字母。如果字符是小写字母,你应该在S的最后加入一个字母Ki.

    保证每次操作后字符串S的长度始终是正数。

    (1<=Q<=10000)

    Output

    一行输出Q个数,以空格隔开,第ii个整数代表第ii次操作后的答案。

    Sample input and output

    Sample Input Sample Output
    17
    qu-uer-ryr-reu-uq
    1 2 1 2 3 4 3 4 5 7 5 7 9 11 9 11 13

    题目分析:

        题目不难看出就是让我们求某个字符串中的本质不同的回文字串的数量。因此我们不难想到建一颗回文树去维护。

        之后只需要模拟加串和减串的过程,不断的建回文树维护相应的字符串即可。

    代码:

    #include <bits/stdc++.h>
    #define maxn 10005
    using namespace std;
    char str[maxn];
    int ans[maxn];
    vector<int>vec;
    struct PAM{//回文树
        int next[maxn][26],fail[maxn],S[maxn],cnt[maxn],len[maxn];
        int id,last,n;
        int newnode(int x){
            for(int i=0;i<26;i++){
                next[id][i]=0;
            }
            len[id]=x;
            cnt[id]=0;
            return id++;
        }
        void inti(){
            id=0;
            newnode(0);
            newnode(-1);
            fail[0]=1;
            n=0;
            S[n]=-1;
            last=0;
        }
        int get_fail(int x){
            while(S[n-len[x]-1]!=S[n]) x=fail[x];
            return x;
        }
        void Insert(int c){
            S[++n]=c;
            int cur=get_fail(last);
            if(!next[cur][c]){
                int now=newnode(len[cur]+2);
                fail[now]=next[get_fail(fail[cur])][c];
                next[cur][c]=now;
            }
            last=next[cur][c];
            cnt[last]++;
        }
        void Get(){
            for(int i=id-1;i>=0;i--){
                cnt[fail[i]]+=cnt[i];
            }
        }
    }pam;
    int main()
    {
        int t;
        scanf("%d",&t);
        scanf("%s",str);
        int len=strlen(str);
        vec.clear();
        memset(ans,0,sizeof(int)*len);
        for(int i=0;i<len;i++){
            pam.inti();//每经历一次操作就重新建树
            if(str[i]=='-') vec.pop_back();
            else vec.push_back(str[i]-'a');
            int siz=vec.size();
            for(int j=0;j<siz;j++){//建树
                pam.Insert(vec[j]);
            }
            pam.Get();
            for(int j=2;j<pam.id;j++){
                ans[i]+=pam.cnt[j];
            }
        }
        for(int i=0;i<len;i++){
            if(i==0) printf("%d",ans[i]);
            else printf(" %d",ans[i]);
        }
        return 0;
    }
    
  • 相关阅读:
    2018年国内就业薪资高的7大编程语言排行
    前端css实现最基本的时间轴
    前端css实现最基本的时间轴
    用Canvas画一个刮刮乐
    用Canvas画一个刮刮乐
    「干货」从菜鸟到大神,前端学习书籍推荐
    洛谷P3379 【模板】最近公共祖先(LCA)
    洛谷 P1359 租用游艇
    位运算...
    洛谷P2782 友好城市
  • 原文地址:https://www.cnblogs.com/Chen-Jr/p/11007207.html
Copyright © 2020-2023  润新知