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. N个数求和(模拟)

    本题的要求很简单,就是求N个数字的和.麻烦的是,这些数字是以有理数分子/分母的形式给出的,你输出的和也必须是有理数的形式. 输入格式: 输入第一行给出一个正整数N(≤100).随后一行按格式a1/b1 ...

  2. [BZOJ4052][Cerc2013]Magical GCD

    [BZOJ4052][Cerc2013]Magical GCD 试题描述 给出一个长度在 100 000 以内的正整数序列,大小不超过 10^12.  求一个连续子序列,使得在所有的连续子序列中,它们 ...

  3. BZOJ 1022: [SHOI2008]小约翰的游戏John【anti-SG】

    Description 小约翰经常和他的哥哥玩一个非常有趣的游戏:桌子上有n堆石子,小约翰和他的哥哥轮流取石子,每个人取的时候,可以随意选择一堆石子,在这堆石子中取走任意多的石子,但不能一粒石子也不取 ...

  4. hdu 1563简单异或Find your present!

    #include<stdio.h> int  main(){  int n,m,s;  while(scanf("%d",&n),n) {   s=0;   w ...

  5. 【ZJOI2017 Round1练习】D2T3 counter(线段树)

    题意: 思路: 预处理出b[i]代表i位置之前比a[i]小的数的个数 以每个数为结尾的组数是线段树中(1,a[i]-1) 对于a[i]换到最后,相当于线段树中(a[i]+1,n)-- 交换后b[i]又 ...

  6. BZOJ2097: [Usaco2010 Dec]Exercise 奶牛健美操

    n<=100000的树,砍S<n条边,求砍完后S+1棵树的最大直径的最小值. 树的直径要小小哒,那考虑一棵子树的情况吧!一棵子树的直径,就是子树根节点各儿子的最大深度+次大深度.就下面这样 ...

  7. apache cgi 模块安装

    apache安装,请参照:http://httpd.apache.org/docs/2.4/ 安装系统: Fedora release 21 (Twenty One)  (x64) 版本:Server ...

  8. 洛谷 P1731 [NOI1999]生日蛋糕

    P1731 [NOI1999]生日蛋糕 题目背景 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层 生日蛋糕,每层都是一个圆柱体. 设从下往上数第i(1<=i<=M ...

  9. Spring Boot应用的启动和停止(Spring Boot应用通过start命令启动)

    Spring Boot,作为Spring框架对“约定优先于配置(Convention Over Configuration)”理念的最佳实践的产物,它能帮助我们很快捷的创建出独立运行.产品级别的基于S ...

  10. CSS 遮罩层、滑出页面

    <style> .panel_bak { position:fixed; bottom:0; display:none; width:100%; margin:0px; padding:5 ...