传送门在这里。

大意:

  给一堆字符串,询问每个字符串有多少子串在所有字符串中出现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树)的更多相关文章

  1. [Codeforces 204E] Little Elephant and Strings

    [题目链接] https://codeforces.com/contest/204/problem/E [算法] 首先构建广义后缀自动机 对于自动机上的每个节点 , 维护一棵平衡树存储所有它所匹配的字 ...

  2. E. Three strings 广义后缀自动机

    http://codeforces.com/problemset/problem/452/E 多个主串的模型. 建立一个广义后缀自动机,可以dp出每个状态的endpos集合大小.同时也维护一个R[]表 ...

  3. CF452E Three strings 广义后缀自动机

    建一个广义后缀自动机统计一下就行,好长时间不敲后缀自动机调了半天~ #include <bits/stdc++.h> using namespace std; namespace IO { ...

  4. CF 666E Forensic Examination——广义后缀自动机+线段树合并

    题目:http://codeforces.com/contest/666/problem/E 对模式串建广义后缀自动机,询问的时候把询问子串对应到广义后缀自动机的节点上,就处理了“区间”询问. 还要处 ...

  5. cf666E. Forensic Examination(广义后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并 首先对所有的\(t_i\)建个广义后缀自动机,这样可以得到所有子串信息. 考虑把询问离线,然后把\(S\)拿到自动机上跑,同时维护一下 ...

  6. Codeforces.666E.Forensic Examination(广义后缀自动机 线段树合并)

    题目链接 \(Description\) 给定串\(S\)和\(m\)个串\(T_i\).\(Q\)次询问,每次询问\(l,r,p_l,p_r\),求\(S[p_l\sim p_r]\)在\(T_l\ ...

  7. [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增

    题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...

  8. MemSQL Start[c]UP 2.0 - Round 1 E - Three strings 广义后缀自动机

    E - Three strings 将三个串加进去,看每个节点在三个串中分别出现了多少次. #include<bits/stdc++.h> #define LL long long #de ...

  9. Codeforces 666E Forensic Examination(广义后缀自动机+线段树合并)

    将所有串(包括S)放一块建SAM.对于询问,倍增定位出该子串所在节点,然后要查询的就是该子串在区间内的哪个字符串出现最多.可以线段树合并求出该节点在每个字符串中的出现次数. #include<b ...

随机推荐

  1. TCP/IP具体解释--TCP的分段和IP的分片

    写在前面: 分组能够发生在运输层和网络层.运输层中的TCP会分段,网络层中的IP会分片.IP层的分片很多其它的是为运输层的UDP服务的,因为TCP自己会避免IP的分片,所以使用TCP传输在IP层都不会 ...

  2. thinkphp5项目--企业单车网站(六)

    thinkphp5项目--企业单车网站(六) 项目地址 fry404006308/BicycleEnterpriseWebsite: Bicycle Enterprise Websitehttps:/ ...

  3. c#多线程操作测试(阻塞线程,结束任务)

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  4. GPU-directX的发展历史

    GPU发展历史: GPU之前的基础: 1962 麻省理工学院的博士伊凡•苏泽兰发表的论文以及他的画板程序奠定了计算机图形学的基础. 1962-1984 没有专门图形处理硬件,由CPU完成 1984 专 ...

  5. Supervisor 的安装与配置教程

    简介 Supervisor是一个进程控制系统. 它是一个C/S系统(注意: 其提供WEB接口给用户查询和控制), 它允许用户去监控和控制在类UNIX系统的进程. 它的目标与launchd, daemo ...

  6. mysql 问题排查语句

    1.查询不是sleep或者有状态的sql select * from `information_schema`.processlist where command !='Sleep' or state ...

  7. Django_视图操作

  8. 最近遇到的若干Web前端问题:disable和readonly,JqueryEasyUI,KindEditor

    最近项目中用到了Jquery Easyui和KindEditor等框架组件,问题真不少啊~  一些看起来很简单理所当然的事情,竟然花费了不少时间,才解决好~  1.readonly和disable的区 ...

  9. jq 克隆 移除table

    function addRow2(node){ var obj = $("tr[name='info']:last"); var objClone = $(obj).clone() ...

  10. JQ each 各种标签

    类选择器: $("input[class=class1]").each(function(){ alert($(this).val()); }); ID选择器: $("i ...