2019牛客暑期多校训练营(第六场)Palindrome Mouse 回文树+dfs
题意:给出一个字符串,将字符串中所有的回文子串全部放入一个集合里,去重后。问这个集合里有几对<a,b>,使得a是b的子串。
思路:一开始想偏了,以为只要求每个回文串的回文后缀的数量加去掉开头结尾字符的数量就可以了。事实上,如果我们把去掉两个字符的字符串称为父节点,那么父节点的回文后缀和自己也能形成这样的pair。
设一个字符串x能产生的贡献为$dp[x]$,我们考虑x能产生的贡献是什么呢?
一个是和自己本身的所有回文后缀结合产生的贡献,这一个可以通过回文树上跳fail来完成。
一个是和自己的父节点结合,这个价值只有1,且要求父节点不是0或者1,当然自己也不能是0或者1.
还有一个是父节点能产生的贡献,这个就考虑到了父节点父节点和自己还有父节点的回文后缀和自己,此处可以通过dfs来得到。
一个子串可能同时是自己的祖先节点和回文后缀,这种情况要标记一下,不能重复计算,比如$aaa$。如果不停的掉fail,那么会跳到最后一个字符$a$,但$a$同时也是自己的父节点。
#pragma GCC optimize (2)
#pragma G++ optimize (2)
#pragma comment(linker, "/STACK:102400000,102400000")
#include<bits/stdc++.h>
#include<cstdio>
#include<vector>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,b,a) for(int i=b;i>=a;i--)
#define clr(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pii pair<int,int >
using namespace std;
typedef long long ll;
ll rd()
{
ll x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
const int maxn=;
char s[maxn];
ll dp[maxn];
int vis[maxn],cat=;
struct Palindromic_Tree
{
struct Node
{
int son[];
int ff,len;
}t[maxn];
int last,tot;
ll ans=;
void init()
{
memset(t,,sizeof(t[])*(tot+));
tot=last=ans=;
t[++tot].len=-;
t[].ff=t[].ff=;
}
void extend(int c,int n)
{
int p=last;
while(s[n-t[p].len-]!=s[n])p=t[p].ff;
if(!t[p].son[c])
{
int v=++tot,k=t[p].ff;
t[v].len=t[p].len+;
while(s[n-t[k].len-]!=s[n])k=t[k].ff;
t[v].ff=t[k].son[c];
t[p].son[c]=v;
}
last=t[p].son[c];
}
void dfs(int x,int fa){
ll cnt=;
int cx=t[x].ff;
vis[x]++;
while(cx!=&&cx!=&&vis[cx]==){vis[cx]++;cnt++;cx=t[cx].ff;
}
dp[x]=cnt;
if(x!=&&x!=&&fa!=&&fa!=)dp[x]=dp[fa]+cnt+;
ans+=dp[x];
rep(i,,){
if(t[x].son[i])dfs(t[x].son[i],x);
}
vis[x]--;
cx=t[x].ff;
while(cnt--){
vis[cx]--;cx=t[cx].ff;
}
} void solve(){
dfs(,),dfs(,);
printf("Case #%d: %lld\n",cat++,ans);
}
}a;
int main(){
int T;
cin>>T;
while(T--){
scanf("%s",s+);
int len=strlen(s+);
a.init();
rep(i,,len){
a.extend(s[i]-'a',i);
}
a.solve();
} }
2019牛客暑期多校训练营(第六场)Palindrome Mouse 回文树+dfs的更多相关文章
- 2019牛客暑期多校训练营(第一场)I dp+线段树
题意 给出n个点,每个点有a,b两个属性,让你从左下角到右上角划一条线,线的左边每个点的贡献是\(a_i\),线的右边每个点的贡献是\(b_i\),使得两部分的总和最大. 分析 找一条折线将点分割开, ...
- 2019牛客暑期多校训练营(第六场)C - Palindrome Mouse (回文自动机)
https://ac.nowcoder.com/acm/contest/886/C 题意: 给出一个串A , 集合S里面为A串的回文字串 , 现在在集合S里面找出多少对(a,b),b为a的字串 分析: ...
- 2019牛客暑期多校训练营(第二场)E.MAZE(线段树+dp)
题意:给你一个n*m的矩阵 你只能向左向右相下走 有两种操作 q次询问 一种是把一个单位翻转(即可走变为不可走 不可走变为可走) 另一种是询问从(1,x) 走到 (n,y)有多少种方案 思路:题目n为 ...
- 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 ...
随机推荐
- es7 async 前置依赖
https://stackoverflow.com/questions/33527653/babel-6-regeneratorruntime-is-not-defined 移动端 px2rem-lo ...
- mysql导入.csv文件出错
1.报错信息 ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cann ...
- android studio 设计任务内容和识别内容界面 (android stuido design task layout)
本人android studio版本是 3.4.1,设计了一个任务内容和识别内容的界面,欢迎大家品尝. 界面显示如下图所示: 实现代码如下: <?xml version="1.0&qu ...
- 6371. 【NOIP2019模拟2019.9.28】基础图论练习题
题目 题目大意 维护一个无向图的割边条数,支持加边和删边. 正解 (PS:这是我很久之前在OJ上打出来的题解,现在直接copy过来) 题解只有一句话,估计没多少人可以看得懂.感觉出题人偷懒不想写题解- ...
- git——创建分支后,切换分支报错(error: pathspec 'master' did not match any file(s) known to git)
error: pathspec 'master' did not match any file(s) known to git 解决办法: 1.查看分支 git branch -a 2.获取所有分支 ...
- pandas for python
http://pandas.pydata.org/pandas-docs/stable/user_guide/index.html 不算太难,需要拿一本线性代数看看矩阵原理即可.重点在于考虑如何运用, ...
- Android 在OnCreate()中获取控件高度与宽度
试过在OnCreate()中获取控件高度与宽度的童鞋都知道,getWidth()与getHeight()方法返回是0,具体原因 看一下Activity的生命周期 就会明白. 上代码: 方法一: int ...
- DOM学习总结(三)DOM访问/操作
DOM访问理解:找到这个标签元素,然后才能对它进行操作 1.getElementById() 方法document.getElementById(""); //通过id名字来找到 ...
- NX二次开发-Block UI C++界面Body Collector(体收集器)控件的获取(持续补充)
Body Collector(体收集器)控件的获取 NX9+VS2012 #include <uf.h> #include <uf_obj.h> UF_initialize() ...
- 牛客Another Distinct Values
题目 我一开始试了一下n=3,发现不行,于是就猜测只有2可以,交了一发,通过了50%.所以我猜测只有偶数可以,奇数都不行. 中间空白部分放n=2的情况就行.因为n=2的情况时,最大只有2,所以我们可以 ...