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

Input
3 1
abc
a
ab
Output
6 1 3 
Input
7 4
rubik
furik
abab
baba
aaabbbababa
abababababa
zero
Output
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 (广义后缀自动机求出现次数)的更多相关文章

  1. codeforces 204E. Little Elephant and Strings(广义后缀自动机,Parent树)

    传送门在这里. 大意: 给一堆字符串,询问每个字符串有多少子串在所有字符串中出现K次以上. 解题思路: 这种子串问题一定要见后缀自动机Parent树Dfs序统计出现次数都是套路了吧. 这道题统计子串个 ...

  2. [Codeforces 204E] Little Elephant and Strings

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

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

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

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

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

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

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

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

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

  7. D. Match & Catch 后缀自动机 || 广义后缀自动机

    http://codeforces.com/contest/427/problem/D 题目是找出两个串的最短公共子串,并且在两个串中出现的次数只能是1次. 正解好像是dp啥的,但是用sam可以方便很 ...

  8. POJ3080 POJ3450Corporate Identity(广义后缀自动机||后缀数组||KMP)

    Beside other services, ACM helps companies to clearly state their “corporate identity”, which includ ...

  9. SPOJ8093Sevenk Love Oimaster(广义后缀自动机)

    Oimaster and sevenk love each other.     But recently,sevenk heard that a girl named ChuYuXun was da ...

随机推荐

  1. Robot Framework中的未解之谜

    今天在写测试用例的时候偶然发现了一个问题: 一.看脚本逻辑上没有问题,但是在引用变量的时候不能成功引用,脚本截图如下: 这个是关键字A的截图,没有参数. 此时在case中引用${phonesign}和 ...

  2. hdu 1711kmp裸题

    #include<stdio.h> #define N 1000050 int text[N],t[N],next[N],n,m; void getnext() { int j=0,k=- ...

  3. Can you answer these queries(spoj 1043)

    题意:多次查询区间最长连续字段和 /* 用线段树维护区间最长子段和,最长左子段和,最长右子段和. */ #include<cstdio> #include<iostream> ...

  4. [CodePlus2017]晨跑

    Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 166  Solved: 125 Description "无体育,不清华".&qu ...

  5. [Usaco2009 Open]工作安排Job

    Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1457  Solved: 687[Submit][Status][Discuss] Descriptio ...

  6. Linux中断处理驱动程序编写

    本章节我们一起来探讨一下Linux中的中断 中断与定时器:中断的概念:指CPU在执行过程中,出现某些突发事件急待处理,CPU暂停执行当前程序,转去处理突发事件,处理完后CPU又返回原程序被中断的位置继 ...

  7. 【algorithm】尾递归

    尾递归和一般的递归不同在对内存的占用,普通递归创建stack累积而后计算收缩,尾递归只会占用恒量的内存(和迭代一样).SICP中描述了一个内存占用曲线,用以上答案中的Python代码为例(普通递归): ...

  8. Friefox清除旧的网页缓存

    Ctrl + F5 适用于调试网页编码时,不断以旧设置显示页面

  9. Angular2.x-服务

    heroes之旅HeroesComponent目前正在获取并显示虚假数据. 在本教程重构之后,HeroesComponent将会精益求精并专注于支持视图.用模拟服务进行单元测试也会更容易. 为什么服务 ...

  10. iOS中3种正则表达式的使用

    1.利用NSPredicate(谓词)匹配 例如匹配有效邮箱: ? 1 2 3 4 NSString *email = @“nijino_saki@163.com”:  NSString *regex ...