• Finding Palindromes


    题目大意:有 N 个字符串,所有的字符串长度不超过 200W 任意俩俩字符串可以自由组合,问组合的字符串是回文串的个数有多少个?
     
    分析:这是一个相当猥琐的字符串处理,因为没有说单个的字符串最少多长,所以很可能会有这样的情况,200w个字符串,每个字符串长度1,或者1个串,这个串的长度是100w, 为了对付这种猥琐的方式可以用一个长为100w的字符串保存所有的串,然后用另一个数组记录每个字符串所在的区间。匹配的时候可以使用trie因为回文串是两端匹配,所以插入trie的时候可以倒着插入,不过查询的时候会出现两种情况,一种是这个字符串已经匹配完,不过他后面匹配的字符串没有完,另一种是这个字符串匹配完还有剩余长度,不管哪种情况都需要判断一下剩余的串是否是回文串,tire里面的保存后缀,匹配串保存的是前缀。
     
    代码如下:
    ================================================================================================================
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    
    const int MAXN = 2e6+7;
    const int oo = 1e9+7;
    
    struct Trie
    {///字典树的节点
        int next[26];
        int leaf;///以这个节点为终点的叶子节点个数
        int count;///后面回文串的数量
    
        void Free()
        {
            leaf = count = 0;
            memset(next, false, sizeof(next));
        }
    
    }trie[MAXN];
    
    int top;///配合字典树使用,top表示没有使用的内存
    int start[MAXN], p[MAXN<<1];
    char MumStr[MAXN], Estr[MAXN<<1];
    bool suffix[MAXN];///后缀是否是回文串
    bool prefix[MAXN];///前缀是否是回文串
    
    void BuildTrie(int n)
    {
        int p = 0;
    
        for(int i=start[n+1]-1; i>=start[n]; i--)
        {///把字符串倒插进去
            int k = MumStr[i] - 'a';
    
            trie[p].count += prefix[i];
    
            if(trie[p].next[k] == 0)
            {
                trie[p].next[k] = ++top;
                trie[top].Free();
            }
            p = trie[p].next[k];
        }
    
        trie[p].leaf += 1;
    }
    void Manacher(int n)
    {
        int i, id=0, len=1;
    
        Estr[0] = '$';
    
        for(i=start[n]; i<start[n+1]; i++)
        {
            Estr[len++] = '#';
            Estr[len++] = MumStr[i];
    
            suffix[i] = false;
            prefix[i] = false;
        }
        Estr[len] = '#';
        Estr[len+1] = 0;
    
        for(i=2; i<len; i++)
        {
            p[i] = 1;
    
            if(p[id]+id > i)
                p[i] = min(p[id*2-i], p[id]+id-i);
    
            while(Estr[ i+p[i] ] == Estr[ i-p[i] ])
                p[i]++;
    
            if(p[id]+id < p[i]+i)
                id = i;
    
            if(p[i] == i)
                prefix[ start[n]+p[i]-2 ] = true;
            if(p[i]+i-1 == len)
                suffix[ start[n+1]-p[i]+1 ] = true;
        }
    }
    int Query(int n)
    {
        int i, p=0, sum = 0;
    
        for(i=start[n]; i<start[n+1]; i++)
        {
            int k = MumStr[i] - 'a';
    
            if(trie[p].next[k] == 0)
                break;
    
            p = trie[p].next[k];
    
            if(suffix[i+1] || i==start[n+1]-1)
                sum += trie[p].leaf;
        }
    
        if(i == start[n+1])
            sum += trie[p].count;
    
        return sum;
    }
    
    int main()
    {
        int N;
    
        while(scanf("%d", &N) != EOF)
        {
            int i, len;
    
            top = 0;
            trie[0].Free();
    
            for(i=1; i<=N; i++)
            {
                scanf("%d%s", &len, MumStr+start[i]);
                start[i+1] = start[i] + len;
    
                Manacher(i);
                BuildTrie(i);
            }
    
            long long ans = 0;
    
            for(i=1; i<=N; i++)
                ans += Query(i);
    
            printf("%lld
    ", ans);
        }
    
        return 0;
    }
    /**
    2
    3 abc
    4 acba
    
    */
  • 相关阅读:
    Redis配置文件详解
    SpingBoot 定时器(跟随Application启动)
    Linux 查找哪些文件包含指定的一个或多个字符串
    帆软报表中sql中出现汉字时乱码
    mysql 匹配奇数、偶数行数据
    vs code 快捷键中英文对照
    前端学习路线汇总
    vscode: Visual Studio Code 常用快捷键1
    vue-router的router.go(n)问题?
    vue2.0 技巧汇总
  • 原文地址:https://www.cnblogs.com/liuxin13/p/4748749.html
Copyright © 2020-2023  润新知