CodeForces-204E:Little Elephant and Strings (广义后缀自动机求出现次数)
The Little Elephant loves strings very much.
He has an array a from n strings, consisting of lowercase English letters. Let's number the elements of the array from 1 to n, then let's denote the element number i as ai. For each string ai (1 ≤ i ≤ n) the Little Elephant wants to find the number of pairs of integers l and r (1 ≤ l ≤ r ≤ |ai|) such that substring ai[l... r] is a substring to at least k strings from array a (including the i-th string).
Help the Little Elephant solve this problem.
If you are not familiar with the basic notation in string problems, you can find the corresponding definitions in the notes.
Input
The first line contains two space-separated integers — n and k (1 ≤ n, k ≤ 105). Next n lines contain array a. The i-th line contains a non-empty string ai, consisting of lowercase English letter. The total length of all strings ai does not exceed 105.
Output
On a single line print n space-separated integers — the i-th number is the answer for string ai.
Please, do not use the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cin, cout streams or the %I64d specifier.
Example
3 1
abc
a
ab
6 1 3
7 4
rubik
furik
abab
baba
aaabbbababa
abababababa
zero
1 0 9 9 21 30 0
题意:给定N和L,输入N个字符串,对于每个字符串,输出其有多少个字串满足在这N个串里出现的次数大于等于K。
思路:广义后缀自动机模板题,或者后缀数组。
注意:注意K>N时直接输出若干个0,不然会超时,GG。
向上传递时我大胆的试了一试Bitset,结果超内存了。但是set没问题。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=;
int N,K,L,times; string s[maxn];
struct SAM
{
int np,p,nq,q,Last,cnt,cur[maxn],sum[maxn];
int maxlen[maxn],fa[maxn],ch[maxn][];
SAM(){ Last=cnt=; }
void add(int x){
np=++cnt; p=Last; Last=np; maxlen[np]=maxlen[p]+;
while(p&&!ch[p][x]) ch[p][x]=np,p=fa[p];
if(!p) fa[np]=;
else{
q=ch[p][x];
if(maxlen[q]==maxlen[p]+) fa[np]=q;
else{
nq=++cnt;
memcpy(ch[nq],ch[q],sizeof(ch[nq]));
cur[nq]=cur[q]; sum[nq]=sum[q];
fa[nq]=fa[q]; fa[np]=fa[q]=nq;maxlen[nq]=maxlen[p]+;
while(p&&ch[p][x]==q) ch[p][x]=nq,p=fa[p];
}
}
while(np){
if(cur[np]==times||sum[np]>=K) break;
sum[np]++; cur[np]=times; np=fa[np];
}
}
void sort()
{ }
void solve(int now)
{
int tp=;long long ans=; L=s[now].length();
for(int i=;i<L;i++) {
tp=ch[tp][s[now][i]-'a'];
int kkk=tp;
while(kkk>){
if(sum[kkk]>=K){ ans+=maxlen[kkk]; break; }
kkk=fa[kkk];
}
}
printf("%lld ",ans);
}
}sam;
int main()
{
scanf("%d%d",&N,&K);
for(int i=;i<=N;i++){
cin>>s[i];
L=s[i].length(); sam.Last=; times=i;
for(int j=;j<L;j++) sam.add(s[i][j]-'a');
}
if(K>N){
for(int i=;i<=N;i++) printf("0 ");
return ;
}
sam.sort();
for(int i=;i<=N;i++) sam.solve(i);
return ;
}
拓扑后set传递。
#include<set>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=;
int N,K,times; char s[maxn];
set<int>Set[maxn];
int a[maxn],b[maxn],sum[maxn],L[maxn],R[maxn];
struct SAM
{
int np,p,nq,q,Last,cnt,maxlen[maxn],fa[maxn],ch[maxn][];
SAM(){ Last=cnt=; }
void add(int x){
np=++cnt; p=Last; Last=np; maxlen[np]=maxlen[p]+;
while(p&&!ch[p][x]) ch[p][x]=np,p=fa[p];
if(!p) fa[np]=;
else{
q=ch[p][x];
if(maxlen[q]==maxlen[p]+) fa[np]=q;
else{
nq=++cnt;
memcpy(ch[nq],ch[q],sizeof(ch[nq]));
fa[nq]=fa[q]; fa[np]=fa[q]=nq;maxlen[nq]=maxlen[p]+;
while(p&&ch[p][x]==q) ch[p][x]=nq,p=fa[p];
}
}
}
void sort()
{
for(int i=;i<=cnt;i++) a[maxlen[i]]++;
for(int i=;i<=cnt;i++) a[i]+=a[i-];
for(int i=;i<=cnt;i++) b[a[maxlen[i]]--]=i;
for(int i=;i<=N;i++){
int tp=;
for(int j=L[i];j<=R[i];j++){
tp=ch[tp][s[j]-'a'];
Set[tp].insert(i);
}
}
for(int i=cnt;i>;i--){
int x=b[i];
sum[x]=Set[x].size();
int y=fa[x];
if(Set[x].size()>Set[y].size()) swap(Set[x],Set[y]);
for(set<int>::iterator it=Set[x].begin();it!=Set[x].end();it++)
Set[y].insert(*it);
}
}
void solve(int now)
{
int tp=; long long ans=;
for(int i=L[now];i<=R[now];i++) {
tp=ch[tp][s[i]-'a'];
int kkk=tp;
while(kkk>){
if(sum[kkk]>=K){ ans+=maxlen[kkk];break;}
kkk=fa[kkk];
}
}
printf("%lld ",ans);
}
}sam;
int main()
{
scanf("%d%d",&N,&K);
for(int i=;i<=N;i++){
L[i]=R[i-]+;
scanf("%s",s+L[i]);
R[i]=L[i]+strlen(s+L[i])-;
sam.Last=;
for(int j=L[i];j<=R[i];j++) sam.add(s[j]-'a');
}
if(K>N){
for(int i=;i<=N;i++) printf("0 ");
return ;
}
sam.sort();
for(int i=;i<=N;i++) sam.solve(i);
return ;
}
CodeForces-204E:Little Elephant and Strings (广义后缀自动机求出现次数)的更多相关文章
- codeforces 204E. Little Elephant and Strings(广义后缀自动机,Parent树)
传送门在这里. 大意: 给一堆字符串,询问每个字符串有多少子串在所有字符串中出现K次以上. 解题思路: 这种子串问题一定要见后缀自动机Parent树Dfs序统计出现次数都是套路了吧. 这道题统计子串个 ...
- [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 { ...
- MemSQL Start[c]UP 2.0 - Round 1 E - Three strings 广义后缀自动机
E - Three strings 将三个串加进去,看每个节点在三个串中分别出现了多少次. #include<bits/stdc++.h> #define LL long long #de ...
- CF 666E Forensic Examination——广义后缀自动机+线段树合并
题目:http://codeforces.com/contest/666/problem/E 对模式串建广义后缀自动机,询问的时候把询问子串对应到广义后缀自动机的节点上,就处理了“区间”询问. 还要处 ...
- D. Match & Catch 后缀自动机 || 广义后缀自动机
http://codeforces.com/contest/427/problem/D 题目是找出两个串的最短公共子串,并且在两个串中出现的次数只能是1次. 正解好像是dp啥的,但是用sam可以方便很 ...
- POJ3080 POJ3450Corporate Identity(广义后缀自动机||后缀数组||KMP)
Beside other services, ACM helps companies to clearly state their “corporate identity”, which includ ...
- SPOJ8093Sevenk Love Oimaster(广义后缀自动机)
Oimaster and sevenk love each other. But recently,sevenk heard that a girl named ChuYuXun was da ...
随机推荐
- 【树形DP】codeforces K. Send the Fool Further! (medium)
http://codeforces.com/contest/802/problem/K [题意] 给定一棵树,Heidi从根结点0出发沿着边走,每个结点最多经过k次,求这棵树的最大花费是多少(同一条边 ...
- SpringBoot Beans管理和自动配置
原 SpringBoot Beans管理和自动配置 火推 02 2017年12月20日 21:37:01 阅读数:220 SpringBoot Beans管理和自动配置 @SpringBootAppl ...
- ie6 js报错汇总
假如ie6是一个非美女的人,那不知道为多少人乱刀砍多少次,假如不幸它是一个美女,那不知道要被多少人轮奸完之后还是乱刀砍死. ie6的js的错误说明总是很隐晦的,它喜欢和捉迷藏.报的行数和错误,常常不知 ...
- php之ThinkPHP的memcached类的修改
php之ThinkPHP的memcached类的修改 在Think\Cache\Driver\Memcached.class.php中,增加方法获取错误信息的方法,方便调试, public funct ...
- 洛谷——P1608 路径统计
P1608 路径统计 题目描述 “RP餐厅”的员工素质就是不一般,在齐刷刷的算出同一个电话号码之后,就准备让HZH,TZY去送快餐了,他们将自己居住的城市画了一张地图,已知在他们的地图上,有N个地方, ...
- JVM内存区域(运行时数据区)划分
前言: 我们每天都在编写Java代码,编译,执行.很多人已经知道Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀),然后由JVM中的类加载器加载各个类的字节码文 ...
- CEF3研究(二)
应用程序结构 每个CEF3应用程序都有一个相同的结构: 提供一个入口函数以初始化CEF和运行每个子进程逻辑和CEF消息处理 提供一个CefApp子类处理某个进程的回调 提供一个CefClinet子类处 ...
- 转: Android 软件开发之如何使用Eclipse Debug调试程序详解(七)
转自: http://www.uml.org.cn/mobiledev/201110092.asp Android 软件开发之如何使用Eclipse Debug调试程序详解(七) 发布于2011- ...
- 使用HDP快速搭建Hadoop开发环境 | Debugo
本文简单记录了一下使用VMware workstation 10.CentOS和HDP 2.0.6(Hadoop 2.2)发行版构建Hadoop开发测试环境的全部流程.这个过程中我遇到了不少问题,也耽 ...
- [RxJS] Implement the `map` Operator from Scratch in RxJS
While it's great to use the RxJS built-in operators, it's also important to realize you now have the ...