codeforces 204E. Little Elephant and Strings(广义后缀自动机,Parent树)
大意:
给一堆字符串,询问每个字符串有多少子串在所有字符串中出现K次以上。
解题思路:
这种子串问题一定要见后缀自动机Parent树Dfs序统计出现次数都是套路了吧。
这道题统计子串个数,那么可以发现,若一个节点所对应的子串出现了K次,那么其贡献就是len,不需要考虑重复。
因为即使出现重复也是在两个位置。
那么只需统计以每个点结束的子串就好了。
之前的Dfs序就很套路了。
只需再跑一遍字符串,更新答案就好了。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
const int N=;
struct sant{
int tranc[];
int len;
int pre;
}s[N];
struct pnt{
int hd;
int ind;
int oud;
int col;
int ans;
}p[N];
struct ent{
int twd;
int lst;
}e[N];
struct int_2{
int l;
int r;
int no;
}d[N];
int n,k;
int siz;
int dfn;
int cnt;
int fin;
char tmp[N];
int ll[N],rr[N];
int col[N];
int lst[N];
int line[N];
int str[N];
int lowbit(int x)
{
return x&(-x);
}
void update(int pos,int x)
{
while(pos&&pos<=dfn)
{
line[pos]+=x;
pos+=lowbit(pos);
}
return ;
}
int query(int pos)
{
int ans=;
while(pos)
{
ans+=line[pos];
pos-=lowbit(pos);
}
return ans;
}
bool cmp(int_2 x,int_2 y)
{
return x.r<y.r;
}
void ade(int f,int t)
{
cnt++;
e[cnt].twd=t;
e[cnt].lst=p[f].hd;
p[f].hd=cnt;
return ;
}
void Insert(int c,int pl)
{
int nwp,nwq,lsp,lsq;
nwp=++siz;
s[nwp].len=s[fin].len+;
p[nwp].col=pl;
for(lsp=fin;lsp&&!s[lsp].tranc[c];lsp=s[lsp].pre)
s[lsp].tranc[c]=nwp;
if(!lsp)
s[nwp].pre=;
else{
lsq=s[lsp].tranc[c];
if(s[lsq].len==s[lsp].len+)
s[nwp].pre=lsq;
else{
nwq=++siz;
s[nwq]=s[lsq];
s[nwq].len=s[lsp].len+;
s[lsq].pre=s[nwp].pre=nwq;
while(s[lsp].tranc[c]==lsq)
{
s[lsp].tranc[c]=nwq;
lsp=s[lsp].pre;
}
}
}
fin=nwp;
}
void Dfs(int x)
{
p[x].ind=++dfn;
col[dfn]=p[x].col;
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
Dfs(to);
}
p[x].oud=++dfn;
col[dfn]=p[x].col;
}
int main()
{
scanf("%d%d",&n,&k);
if(k>n)
{
for(int i=;i<=n;i++)
printf("%d ",);
return ;
}
fin=++siz;
for(int i=;i<=n;i++)
{
ll[i]=rr[i-]+;
rr[i]=rr[i-];
fin=;
scanf("%s",tmp);
int len=strlen(tmp);
for(int j=;j<len;j++)
str[++rr[i]]=tmp[j]-'a';
for(int j=ll[i];j<=rr[i];j++)
{
Insert(str[j],i);
}
} for(int i=;i<=siz;i++)
ade(s[i].pre,i);
Dfs();
for(int i=;i<=siz;i++)
d[i]=(int_2){p[i].ind,p[i].oud,i};
std::sort(d+,d+siz+,cmp);
int r=;
for(int i=;i<=siz;i++)
{
while(r<=d[i].r)
{
if(!col[r])
{
r++;
continue;
}
if(lst[col[r]])
update(lst[col[r]],-);
update(r,);
lst[col[r]]=r;
r++;
}
r--;
p[d[i].no].ans=query(d[i].r)-query(d[i].l-);
}
for(int i=;i<=n;i++)
{
long long int ans=;
int root=;
for(int j=ll[i];j<=rr[i];j++)
{
root=s[root].tranc[str[j]];
while(p[root].ans<k)
root=s[root].pre;
ans+=(long long)s[root].len;
}
printf("%I64d ",ans);
}
puts("");
return ;
}
codeforces 204E. Little Elephant and Strings(广义后缀自动机,Parent树)的更多相关文章
- [Codeforces 204E] Little Elephant and Strings
[题目链接] https://codeforces.com/contest/204/problem/E [算法] 首先构建广义后缀自动机 对于自动机上的每个节点 , 维护一棵平衡树存储所有它所匹配的字 ...
- E. Three strings 广义后缀自动机
http://codeforces.com/problemset/problem/452/E 多个主串的模型. 建立一个广义后缀自动机,可以dp出每个状态的endpos集合大小.同时也维护一个R[]表 ...
- CF452E Three strings 广义后缀自动机
建一个广义后缀自动机统计一下就行,好长时间不敲后缀自动机调了半天~ #include <bits/stdc++.h> using namespace std; namespace IO { ...
- CF 666E Forensic Examination——广义后缀自动机+线段树合并
题目:http://codeforces.com/contest/666/problem/E 对模式串建广义后缀自动机,询问的时候把询问子串对应到广义后缀自动机的节点上,就处理了“区间”询问. 还要处 ...
- cf666E. Forensic Examination(广义后缀自动机 线段树合并)
题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并 首先对所有的\(t_i\)建个广义后缀自动机,这样可以得到所有子串信息. 考虑把询问离线,然后把\(S\)拿到自动机上跑,同时维护一下 ...
- Codeforces.666E.Forensic Examination(广义后缀自动机 线段树合并)
题目链接 \(Description\) 给定串\(S\)和\(m\)个串\(T_i\).\(Q\)次询问,每次询问\(l,r,p_l,p_r\),求\(S[p_l\sim p_r]\)在\(T_l\ ...
- [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增
题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...
- MemSQL Start[c]UP 2.0 - Round 1 E - Three strings 广义后缀自动机
E - Three strings 将三个串加进去,看每个节点在三个串中分别出现了多少次. #include<bits/stdc++.h> #define LL long long #de ...
- Codeforces 666E Forensic Examination(广义后缀自动机+线段树合并)
将所有串(包括S)放一块建SAM.对于询问,倍增定位出该子串所在节点,然后要查询的就是该子串在区间内的哪个字符串出现最多.可以线段树合并求出该节点在每个字符串中的出现次数. #include<b ...
随机推荐
- USACO2011 Jan:公司利润
简要题意: 奶牛开了家公司,已经连续运作了N 天.它们在第i 天获得了Ai元的利润,不过有些天是亏钱的,这种情况下利润就是一个负数.约翰想为它们写个新闻,吹嘘它们的惊人业绩.请你帮助他选出一段连续的日 ...
- ASE加、解密
AES已经变成目前对称加密中最流行算法之一:AES可以使用128.192.和256位密钥,并且用128位分组加密和解密数据. /** * 加密 * * @param content 需要加密的内容 * ...
- 洛谷T21776 子序列
题目描述 你有一个长度为 nn 的数列 \{a_n\}{an} ,这个数列由 0,10,1 组成,进行 mm 个的操作: 1~l~r1 l r :把数列区间 [l, r][l,r] 内的所有数取反. ...
- GridView单元格取值显示为
在通过GridView取一个单元格(cell)的值时,数据库中为NULL,而页面上显示为空格.发现通过gridview.cell[i].text取出来的值为 ,导致获取数据出现问题. 解决方法: 一. ...
- Centos7最小化安装后再安装图形界面
1. yum -y groupinstall "X Window System" 2. yum -y groupinstall "GNOME Desktop" ...
- uniq---报告或忽略文件中的重复行
uniq命令用于报告或忽略文件中的重复行,一般与sort命令结合使用. 语法 uniq(选项)(参数) 选项 -c或——count:在每列旁边显示该行重复出现的次数: -d或--repeated:仅显 ...
- CSUOJ 1542 Flipping Parentheses
ACM International Collegiate Programming Contest Asia Regional Contest, Tokyo, 2014–10–19 Problem G ...
- 洛谷——P1155 双栈排序
题目描述 Tom最近在研究一个有趣的排序问题.如图所示,通过2个栈S1和S2,Tom希望借助以下4种操作实现将输入序列升序排序. 操作a 如果输入序列不为空,将第一个元素压入栈S1 操作b 如果栈S1 ...
- 洛谷 P1877 [HAOI2012]音量调节
P1877 [HAOI2012]音量调节 题目描述 一个吉他手准备参加一场演出.他不喜欢在演出时始终使用同一个音量,所以他决定每一首歌之前他都需要改变一次音量.在演出开始之前,他已经做好一个列表,里面 ...
- 手动脱FSG壳实战
作者:Fly2015 对于FSG壳.之前没有接触过是第一次接触.这次拿来脱壳的程序仍然是吾爱破解论坛破解培训的作业3的程序.对于这个壳折腾了一会儿,后来还是被搞定了. 1.查壳 首先对该程序(吾爱破解 ...