BZOJ3473&&BZOJ3277串

题面

自己找去

HINT

对于所有串建立一个广义后缀自动机,对于每一个节点开一个set表示这个节点接受的子串在哪些串里出现过,然后在parent tree上做启发式合并,理论复杂度应该是\(nlog_{n}^2\)。

广义后缀自动机

这个广义后缀自动机在建立的时候和后缀自动机时是基本差不多的,就是在每加入一个新串的时候,把\(last=root\)就好了

如何找匹配大等于k次

首先因为每个节点的fa表示的子串都是现在这个节点的后缀,所以fa出现的次数一定\(>=\)当前节点出现的次数(这个东西可以感性认知进行证明),另外,如果一个子串出现次数小等于k,在这个子串后面加一个字符后它的出现次数也不可能大于k次

一句话题解

建立一个广义后缀自动机,然后在每个节点上开个set记录在几个串上出现,然后parent tree上启发式合并set,查询答案的时候不断往父亲节点跳,直到满足条件,然后\(\sum{node[u].len}\)

#include<bits/stdc++.h>
#include<set>
using namespace std;
const int maxn=200010;
inline int read(){
int w=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
w=(w<<3)+(w<<1)+ch-48;
ch=getchar();
}
return w*f;
}
int n,m;
bool debug;
set<int> s[maxn];
set<int>::iterator it;
struct SUFFIXAUTOMATON{
struct Node{
int len,fa;
map<int,int> ch;
}node[2000010];
int lst,root,tot;
inline void init(){
lst=root=tot=1;return;
}
inline void extend(int now,int id){
int p=lst;tot++;lst=tot;int np=tot;
node[np].len=node[p].len+1;s[np].insert(id);
while(p&&!node[p].ch[now]){
node[p].ch[now]=np;
p=node[p].fa;
}
if(!p) node[np].fa=1;
else{
int q=node[p].ch[now];
if(node[q].len==node[p].len+1){
node[np].fa=q;
}
else{
int nq=++tot;node[nq]=node[q];
node[nq].len=node[p].len+1;
node[q].fa=nq;node[np].fa=nq;
while(p&&node[p].ch[now]==q){
node[p].ch[now]=nq;
p=node[p].fa;
}
}
}
}
}SAM;
string ch[maxn];
int sum[maxn];
struct Edge{
int from,to,next;
}edge[maxn*6];
int cnt,head[maxn];
inline void addedge(int u,int v){
cnt++;
edge[cnt].from=u;
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt;
}
inline void dfs(int u){
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;dfs(v);
if(s[u].size()<s[v].size()) swap(s[u],s[v]);
for(it=s[v].begin();it!=s[v].end();it++){
s[u].insert(*it);
}
}
sum[u]=s[u].size();
return;
}
int main(){
n=read();m=read();SAM.init();
for(int i=1;i<=n;i++){
cin>>ch[i];int len=ch[i].length();
for(int j=0;j<len;j++){
SAM.extend(ch[i][j]-'a'+1,i);
}
SAM.lst=1;
}
for(int i=1;i<=SAM.tot;i++){
if(SAM.node[i].fa) addedge(SAM.node[i].fa,i);
}
dfs(SAM.root);
if(m>n){
for(int i=1;i<=n;i++){
printf("0 ");
}
return 0;
}
for(int i=1;i<=n;i++){
long long ans=0;int u=SAM.root;int len=ch[i].length();
for(int j=0;j<len;j++){
u=SAM.node[u].ch[ch[i][j]-'a'+1];
while(sum[u]<m) u=SAM.node[u].fa;
ans+=SAM.node[u].len;
}
printf("%lld ",ans);
}
return 0;
}

你以为这就完了吗,naive

我在写最后那个统计答案的时候,想的做法长这样

for(int i=1;i<=n;i++){
long long ans=0;int u=SAM.root;int len=ch[i].length();
for(int j=0;j<len;j++){
u=SAM.node[u].ch[ch[i][j]-'a'+1];int p=u;
while(sum[p]<m) p=SAM.node[p].fa;
ans+=SAM.node[p].len;
}
printf("%lld ",ans);
}

我是想每次匹配完向上跳,但是在bzoj上它TLE了,然后我想了一个妙妙做法,并查集优化

inline int find(int x){
if(sum[x]>=m) return x;
else return f[x]=find(f[x]);
}

然后跑得飞快,就过了

BZOJ3473&&BZOJ3277串的更多相关文章

  1. [BZOJ3473][BZOJ3277]字符串

    [BZOJ3473][BZOJ3277]字符串 试题描述 给定 \(n\) 个字符串,询问每个字符串有多少子串(不包括空串)是所有 \(n\) 个字符串中至少 \(k\) 个字符串的子串? 输入 第一 ...

  2. bzoj3473: 字符串 && bzoj3277串

    3473: 字符串 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 121  Solved: 53[Submit][Status][Discuss] D ...

  3. bzoj3473字符串&bzoj3277串

    题意:给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串.注意本质相同的子串多次出现算多次,如1 1 aaa这组数据答案为6,贡献1WA.代码里有些部分是为了 ...

  4. 【bzoj3277/bzoj3473】串/字符串 广义后缀自动机

    题目描述 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). 输入 第一行两个整数n,k.接下来n行每行一个 ...

  5. BZOJ3277 串 和 BZOJ3473 字符串

    字符串 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? 分析 参照自为风月马前卒和Candy?的题解. 广义后缀自动机不就是把很多串的SAM建到了一个S ...

  6. BZOJ3277 串(后缀数组+二分答案+主席树)

    因为不会SAM,考虑SA.将所有串连起来并加分隔符,每次考虑计算以某个位置开始的子串有多少个合法. 对此首先二分答案,找到名次数组上的一个区间,那么只需要统计有多少个所给串在该区间内出现就可以了.这是 ...

  7. BZOJ3277——串

    0.题意:给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). 1.分析:这个题我问了吴大爷做法 首先建立后缀自动机,然后利用离线搞出每一个 ...

  8. bzoj3277 串 (后缀数组+二分答案+ST表)

    常见操作:先把所有串都连到一起,但中间加上一个特殊的符号(不能在原串中/出现过)作为分割 由于全部的子串就等于所有后缀的所有前缀,那我们对于每一个后缀,去求一个最长的前缀,来满足这个前缀在至少K个原串 ...

  9. 【文文殿下】[BZOJ3277] 串

    Description 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中 至少k个字符串的子串(注意包括本身) Input 第一行两个整数n,k ...

随机推荐

  1. AJAX传输图片文件

    AJAX传输 例:const xhr = new XMLHttpRequest(); // 此方法因为状态改变被调用多次,实测执行三次(1->2->4) xhr.onreadystatec ...

  2. 轻松理解JS中的面向对象,顺便搞懂prototype和__proto__

    这篇文章主要讲一下JS中面向对象以及 __proto__,ptototype和construcator,这几个概念都是相关的,所以一起讲了. 在讲这个之前我们先来说说类,了解面向对象的朋友应该都知道, ...

  3. 数据分析之pandas库--series对象

    1.Series属性及方法 Series是Pandas中最基本的对象,Series类似一种一维数组. 1.生成对象.创建索引并赋值. s1=pd.Series() 2.查看索引和值. s1=Serie ...

  4. xmake v2.3.1 发布, 无缝对接其他构建系统

    最近对xmake内部做了不少的重构来改进,并且新增了不少实用的新特性,欢迎来体验. 项目源码 官方文档 一些新特性: 一键编译其他构建系统维护的项目,实现无缝对接,并且支持交叉编译(比如autotoo ...

  5. 4.【Spring Cloud Alibaba】服务容错-sentinel

    雪崩效应 常见容错方案 超时 限流 仓壁模式 断路器模式 断路器三态转换 使用Sentinel实现容错 什么是Sentinel https://github.com/alibaba/Sentinel ...

  6. 记网站部署中一个奇葩BUG

    网页中引用的文件名不要带 adv 等 近日在写好一个网页后就把他部署到apache上测试,结果用chrome访问时有个背景图片总显示不出来,但是用firefox等却一切正常, 关键是我用windows ...

  7. Head First设计模式——代理模式

    在HeadFirst设计模式中代理模式用了比较多的篇幅来讲解,其中的例子我感觉有些繁琐,所以我们这篇就不按照惯例用例子来阐述代理模式了.我们直接进入正题,分析模式本身的设计和解决的问题. 远程代理模式 ...

  8. Android中使用画笔和画布绘制一个矩形

    场景 在Android中画笔使用Paint类,画布使用Canvas类来表示. 绘图的基本步骤 首先编写一个继承自View的自定义View类,然后重写其onDraw方法,最后把自定义的view添加到ac ...

  9. 使用jdbc将mysql数据库中的内容封装为指定对象的list集合

    使用jdbc将mysql数据库中的内容封装为指定对象的list集合 public List<User> findAll() { private JdbcTemplate template ...

  10. Linux_simpl shell-利用Shell脚本for循环输出系统中的用户及其Shell

    [root@localhost ~]# vim user.sh 1 #!/bin/bash 2 for i in `cut -d ":" -f1 /etc/passwd`; 3 d ...