2019牛客暑期多校训练营(第六场)C Palindrome Mouse (回文树+DFS)
题意
给一个字符串s,然后将s中所有本质不同回文子串放到一个集合S里面,问S中的两个元素\(a,b\)满足\(a\)是\(b\)的子串的个数。
分析
首先要会回文树(回文自动机,一种有限状态自动机)
然后可以很轻松的求出来S集合,我们拿出一个样例画出回文树看一下
abacaba

注: 上图中结点序号只是为了方便描述,与实际建树并不一定相同
0和1分别为偶数根和奇数根,黄边为fail边,总共有7个本质不同的回文串。
在计算答案时,我们从上到下统计,例如计算aba作为母串时的答案,那么子串有\(a\),\(b\)两个,
在计算\(bacab\)时,有\(aca, a, c, b,\) 四个。不难发现,如果把黄边也加入到整个树后,变成一张图,当我们计算某一结点(具体意义为一个回文串,比如7号节点)的答案时,我们要计算它的"祖先"(具有实际意义,即代表一个回文串,例如7号结点祖先为2,3,4,6)。
为了不重复记录,有必要标记我们已经考虑过的结点(也就是计算一个答案之后(比如7)再计算它的子节点的答案时(比如8),我们要把子节点的fail所指结点(比如5)和它自己(7)算进去),而在加这些新结点进行计算时要保证他们之前没有考虑过(比如5,但是7就不需要了,7肯定在之前没有考虑过)
但是不能只对5号结点标记访问,还需要对7标记已经访问,你可以看下面这个例子

在计算7号时,我们要把7号fail所指结点加到答案中去,但是按照我们之前的计算流程可以发现,i 已经在\(ehihe\)的祖先中了,所以不能重复添加。(因为这个坑wa了一发)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100010;
int T;
char s[N];
int n;
ll res;
namespace PAT{
    const int SZ = 2e5+10;
    int ch[SZ][26],fail[SZ],cnt[SZ],len[SZ],tot,last,dep[SZ];
    int vis[SZ];
    void init(int n){
        for(int i=0;i<=n+10;i++){
            fail[i] = cnt[i] = len[i] = vis[i] = dep[i] = 0;
            for(int j=0;j<26;j++)ch[i][j] = 0;
        }
        s[0] = -1;fail[0] = 1;last = 0;
        len[0] = 0;len[1] = -1,tot = 1;
        dep[0] = dep[1] = 0;
    }
    inline int newnode(int x){
        len[++tot] = x;return tot;
    }
    inline int getfail(int x,int n){
        while(s[n-len[x]-1] != s[n])x = fail[x];
        return x;
    }
    void create(char *s,int n){
        s[0] = -1;
        for(int i=1;i<=n;++i){
            int t = s[i]- 'a';
            int p = getfail(last,i);
            if(!ch[p][t]){
                int q = newnode(len[p]+2);
                fail[q] = ch[getfail(fail[p],i)][t];
                ch[p][t] = q;
            }
            ++cnt[last = ch[p][t]];
        }
    }
    int dfs(int p,ll tot){
        //printf("%d %d\n",p,tot);
        res += tot;
        int isadd = (p!=0&&p!=1);//如果爸爸是0号和1号,没实际意义,不计入答案
        vis[p] = 1;
        for(int i=0;i<26;i++){
            if(ch[p][i]){
                int nxt = ch[p][i];
                if(vis[fail[nxt]])
                    dfs(nxt,tot+isadd);
                else{
                    vis[fail[nxt]] = 1;
                    int isaddfail = (fail[nxt]!=0 && fail[nxt] != 1);
                    dfs(nxt,tot+isadd+isaddfail);
                    vis[fail[nxt]] = 0;
                }
            }
        }
        vis[p] = 0;
    }
    void calc(){
        dfs(0,0);
        dfs(1,0);
    }
}
int main(){
    scanf("%d",&T);
    int cas = 0;
    while(T--){
        scanf("%s",s+1);
        n = strlen(s+1);
        PAT::init(n);
        PAT::create(s,n);
        res = 0;
        PAT::calc();
        printf("Case #%d: %lld\n",++cas,res);
    }
    return 0;
}
												
											2019牛客暑期多校训练营(第六场)C Palindrome Mouse (回文树+DFS)的更多相关文章
- 2019牛客暑期多校训练营(第六场)C - Palindrome Mouse (回文自动机)
		
https://ac.nowcoder.com/acm/contest/886/C 题意: 给出一个串A , 集合S里面为A串的回文字串 , 现在在集合S里面找出多少对(a,b),b为a的字串 分析: ...
 - 2019牛客暑期多校训练营(第六场)Palindrome Mouse     回文树+dfs
		
题目传送门 题意:给出一个字符串,将字符串中所有的回文子串全部放入一个集合里,去重后.问这个集合里有几对<a,b>,使得a是b的子串. 思路:一开始想偏了,以为只要求每个回文串的回文后缀的 ...
 - 2019牛客暑期多校训练营(第六场)J Upgrading Technology
		
传送门 题意: 就是给你n个技能,每个技能最高升到m级,每升一级就是耗费Cij钱,这个Cij可能是负的,如果所有技能都升到或者说超过j等级,就会获得Dj钱,这个Dj也有可能是负值,让你求你最多得到多少 ...
 - 2019牛客暑期多校训练营(第九场)A:Power of Fibonacci(斐波拉契幂次和)
		
题意:求Σfi^m%p. zoj上p是1e9+7,牛客是1e9: 对于这两个,分别有不同的做法. 前者利用公式,公式里面有sqrt(5),我们只需要二次剩余求即可. 后者mod=1e9,5才 ...
 - 2019牛客暑期多校训练营(第一场)A题【单调栈】(补题)
		
链接:https://ac.nowcoder.com/acm/contest/881/A来源:牛客网 题目描述 Two arrays u and v each with m distinct elem ...
 - 2019牛客暑期多校训练营(第一场) B	Integration (数学)
		
链接:https://ac.nowcoder.com/acm/contest/881/B 来源:牛客网 Integration 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 5242 ...
 - 2019牛客暑期多校训练营(第一场) A	Equivalent Prefixes ( st 表 + 二分+分治)
		
链接:https://ac.nowcoder.com/acm/contest/881/A 来源:牛客网 Equivalent Prefixes 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/ ...
 - 2019牛客暑期多校训练营(第二场)F.Partition problem
		
链接:https://ac.nowcoder.com/acm/contest/882/F来源:牛客网 Given 2N people, you need to assign each of them ...
 - 2019牛客暑期多校训练营(第一场)A	Equivalent Prefixes(单调栈/二分+分治)
		
链接:https://ac.nowcoder.com/acm/contest/881/A来源:牛客网 Two arrays u and v each with m distinct elements ...
 - [状态压缩,折半搜索] 2019牛客暑期多校训练营(第九场)Knapsack Cryptosystem
		
链接:https://ac.nowcoder.com/acm/contest/889/D来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言52428 ...
 
随机推荐
- 当音乐学博士搞起编程,用一本书改变了Java世界!
			
前言 说到Spring,也许现在的开发者们最先想到的是 Josh Long 超快的语速与现场代码能力,让很多Java开发者折服. 然后Spring的历史上,最传奇的还是要数其创始人:Rod Johns ...
 - mysql 应用 持续更新2 转载
			
作者:彼岸Queen旅行链接:https://www.zhihu.com/question/27334963/answer/266624031来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非 ...
 - 【SpringMVC】SpringMVC 响应数据
			
SpringMVC 响应数据 文章源码 返回值分类 返回值是字符串 Controller 方法返回字符串可以指定逻辑视图的名称,通过视图解析器解析为物理视图的地址. @Controller @Requ ...
 - springboot 和 mongdb连接问题 Exception in thread "main" com.mongodb.MongoSecurityException:
			
1 Exception in thread "main" com.mongodb.MongoSecurityException: Exception authenticating ...
 - /etc/hosts导致的问题
			
今天安装完成orzdba之后,执行./orzdba -l 报如下错误: Usage: Socket::inet_ntoa(ip_address_sv) at /var/lib/mysql/trunk/ ...
 - 【Oracle】 并行查询
			
所谓并行执行,是指能够将一个大型串行任务(任何DML,一般的DDL)物理的划分为叫多个小的部分,这些较小的部分可以同时得到处理.何时使用并行执行:1.必须有一个非常大的任务 2.必须有充足的资源(CP ...
 - library cache pin解决方法
			
library cache pin大部分都是因为编译存储过程造成的 查找造成问题的数据库对象(一般为存储过程) SELECT * FROM v$session_wait WHERE event = ' ...
 - 安装macosx10.13high serria
			
本教程所需资源下载链接: 链接:https://pan.baidu.com/s/1wGTezXz6zGvtlwpv6mMoSg 提取码:r6n9 安装VMware workstation 16.0,安 ...
 - 24V转3.3V芯片,同步降压调节器
			
PW2312是一个高频,同步,整流,降压,开关模式转换器与内部功率MOSFET.它提供了一个非常紧凑的解决方案,以实现1.5A的峰值输出电流在广泛的输入电源范围内,具有良好的负载和线路调节. PW23 ...
 - 精通MySQL之架构篇
			
老刘是即将找工作的研究生,自学大数据开发,一路走来,感慨颇深,网上大数据的资料良莠不齐,于是想写一份详细的大数据开发指南.这份指南把大数据的[基础知识][框架分析][源码理解]都用自己的话描述出来,让 ...