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. ZeptoLab Code Rush 2015 C. Om Nom and Candies [ 数学 ]

    传送门 C. Om Nom and Candies time limit per test 1 second memory limit per test 256 megabytes input sta ...

  2. Java面试题总结之数据库与SQL语句

    1.有3 个表,表结构如下: Student 学生表(学号,姓名,性别,年龄,组织部门) Course 课程表(编号,课程名称) Sc 选课表(学号,课程编号,成绩).    1)写一个SQL 语句, ...

  3. Hive安装中遇到过的坑

    实现说明每一个用户的环境都有细微的不一致,所以这里只是个人经过这些坑的处理,但是不意味着所有处理都是这样的操作,仅作为参考. 第一个坑 数据库安装,数据库最好装在Linux上,一直出了很多错,这里有一 ...

  4. MySQL命令行自动补全表名

    注意:在命令行下只有切换到数据库之后,才能补全表名,对于命令是不能补全的. 1.my.conf增加如下配置: [mysql] #no-auto-rehash auto-rehash #添加auto-r ...

  5. Android切图注意事项

    1.App Logo大小共五种: 48*48 72*72 96*96 144*144 192*192 2. App启动页所需尺寸: 320×480 480×800 720*1280 1080*1920 ...

  6. Android拍照、摄像方向旋转的问题 代码具体解释

    近期做了个拍照.摄像的应用.遇到了拍照.摄像的图像相对于现实.翻转了90度.原因:相机这个硬件的角度是横屏的角度,所以会出现都是横屏的. 1.照相.摄影预览图像的正确角度显 示: public sta ...

  7. 重载OverLoad。隐藏new

    <1> using System; using System.Collections.Generic; using System.Linq; using System.Text; name ...

  8. The data property "dialogVisble" is already declared as a prop. Use prop default value instead报错原因

    vue中使用props传递数据就不能在子组件的data中用同样的名字(比如dialogVisble)了,否则会报错.解决方法直接去掉data中的相同名字改为其他的.

  9. win7下装ubuntu双系统后无法进入win7的解决方法

    本来电脑的系统是win7,然后用u盘装了ubuntu之后可能会出现开机没有引导界面而直接进入ubuntu系统的情况. 原因:没有设置gurb引导 解决方法:需要更新gurb来使ubuntu识别出win ...

  10. php事务操作示例

    <?php //数据库连接 $conn = mysql_connect('localhost', 'root', '');mysql_select_db('test', $conn); /* 支 ...