题目大意

给定\(n\)个字符串和\(k\)

对于每个字符串,输出它有多少个子串至少是\(k\)个字符串的子串(包括自己)

分析

建出广义后缀自动机

至少是\(k\)个字符串的子串就是求子树内不同数个数

考虑怎么统计答案

不要做本质不同子串做傻了

这题是问有多少个子串,子串相同位置不同是可以重复统计的

直接找字符串的每个后缀,它们前缀对应的子串开始位置都是不同的,不会算重

统计的就是每个后缀对应的节点 到跟路径上 有多少合法

dfs预处理一下树上前缀和就好

solution

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int M=200007; inline int rd(){
int x=0;bool f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
for(;isdigit(c);c=getchar()) x=x*10+c-48;
return f?x:-x;
} LL sum[M];
int n,m;
char s[M];
int last,tot;
int stp[M];
int ch[M][26];
int fa[M];
int que[M],ed[M];
int q[M],tq;
int dfn[M],sz[M],tdfn;
int pre[M][20],Mx,dep[M]; struct edge{int y,nxt;};
struct vec{
int g[M],te;
edge e[M];
vec(){memset(g,0,sizeof(g));te=0;}
void clear(){memset(g,0,sizeof(g));te=0;}
inline void push(int x,int y){e[++te].y=y;e[te].nxt=g[x];g[x]=te;}
inline int& operator () (int &x){return g[x];}
inline edge& operator [] (int &x){return e[x];}
}go; int newnode(int ss){
stp[++tot]=ss;
return tot;
} int ext(int p,int q,int d){
int nq=newnode(stp[p]+1);
fa[nq]=fa[q]; fa[q]=nq;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
for(;p&&ch[p][d]==q;p=fa[p]) ch[p][d]=nq;
return nq;
} int sam(int p,int d){
int np=ch[p][d];
if(np) return (stp[p]+1==stp[np]) ? np : ext(p,np,d); np=newnode(stp[p]+1);
for(;p&&!ch[p][d];p=fa[p]) ch[p][d]=np;
if(!p) fa[np]=1;
else{
int q=ch[p][d];
fa[np]= (stp[p]+1==stp[q]) ? q : ext(p,q,d);
}
return np;
} int dfs(int x){
dfn[x]=++tdfn;
sz[x]=1;
int p,y;
for(p=go(x);p;p=go[p].nxt){
y=go[p].y;
dep[y]=dep[x]+1;
pre[y][0]=x;
dfs(y);
sz[x]+=sz[y];
}
} bool cmp(int x,int y){
return dfn[x]<dfn[y];
} int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int t=Mx;t>=0;t--)
if(dep[pre[x][t]]>=dep[y]) x=pre[x][t];
if(x==y) return x;
for(int t=Mx;t>=0;t--)
if(pre[x][t]!=pre[y][t]) x=pre[x][t],y=pre[y][t];
return pre[x][0];
} int c[M]; inline int lb(int x){return x&(-x);} inline int add(int x,int d){
for(;x<=tdfn;x+=lb(x)) c[x]+=d;
} inline int get(int x){
int res=0;
for(;x>0;x-=lb(x)) res+=c[x];
return res;
} inline int get(int x,int y){
return get(y)-get(x-1);
} void vtree(int l,int r){
int i,x,p,y;
tq=0;
for(i=l;i<=r;i++) q[++tq]=que[i];
sort(q+1,q+tq+1,cmp);
for(i=1;i<=tq;i++) add(dfn[q[i]],1);
for(i=2;i<=tq;i++) add(dfn[LCA(q[i],q[i-1])],-1);
} void gao(int x){
int p,y;
for(p=go(x);p;p=go[p].nxt){
y=go[p].y;
if(get(dfn[y],dfn[y]+sz[y]-1)>=m) sum[y]=sum[x]+stp[y]-stp[x];
else sum[y]=sum[x];
gao(y);
}
} int main(){ int i,j,p; n=rd(),m=rd();
tot=1;
for(i=1;i<=n;i++){
scanf("%s",s+1);
last=1;
p=strlen(s+1);
for(j=p;j>0;j--){
last=sam(last,s[j]-'a');//***
que[++tq]=last;
}
ed[i]=tq;
}
for(i=2;i<=tot;i++) go.push(fa[i],i);
dfs(1);
Mx=log2(tot);
for(j=1;j<=Mx;j++)
for(i=1;i<=tot;i++) pre[i][j]=pre[pre[i][j-1]][j-1];
for(i=1;i<=n;i++) vtree(ed[i-1]+1,ed[i]);
gao(1);
for(i=1;i<=n;i++){
LL ans=0;
for(j=ed[i-1]+1;j<=ed[i];j++)
ans+=sum[que[j]];
printf("%lld\n",ans);
} return 0;
}

最新文章

  1. css样式之border-image
  2. Overview of OpenCascade Library
  3. [整理]FPGA学习资料汇总
  4. 原 JQuery监听页面滚动总结
  5. Nmap扫描手册
  6. 设置type为file的input标签选择图片类型
  7. python学习笔记:Day01
  8. hdu 1713 相遇周期
  9. GIT:本地有更改,但强制作远程仓库里作更新
  10. 性能比较工具runstats
  11. 在html页头设置不缓存
  12. 分布式版本控制系统Git-----3.图形化Tortoisegit创建本地库并且提交到远程服务器上
  13. Maze
  14. PHP UEditor富文本编辑器 显示 后端配置项没有正常加载,上传插件不能正常使用
  15. 自己动手实践 spring retry 重试框架
  16. Jeff Atwood:软件工程已死?
  17. eggjs 框架代理调试 SELF_SIGNED_CERT_IN_CHAIN 报错解决方案
  18. spring事物与传播行为
  19. mysql 让id字段 以1000 形式开头
  20. 谷歌技术&quot;三宝&quot;之BigTable

热门文章

  1. 操作系统(2)_进程管理_李善平ppt
  2. 循环引用问题 -- dealloc方法不执行
  3. vue学习之路 - 2.基本操作(上)
  4. HH的项链题解(离线思想+链表+树状数组)
  5. Too Rich HDU - 5527 (贪心+dfs)
  6. (77)zabbix主动、被动检测的详细过程与区别
  7. ATM-interface-bank
  8. 第8课 Thinkphp 5 update判断修改成功与失败 Thinkphp5商城第四季
  9. eclipse 插件,直接打开文件路径
  10. 免费生成https证书以及配置