max:即代码中 len 变量,它表示该状态能够接受的最长的字符串长度。
min:表示该状态能够接受的最短的字符串长度。实际上等于该状态的 fail 指针指向的结点的 len + 1。
max-min+1:表示该状态能够接受的不同的字符串数。

那么在HDU 3518 中。
求的是,不相交且出现次数大于2的子串个数。
我们这么想,如果你把一个串直接塞进后缀自动机里面,比较难以处理(不是没有办法,只是我看不太懂那是怎么回事)不相交的问题。那么我们就想到将字符串拆成两部分,然后两部分分别hash,在一个串里找另一个串中是否存在一个hash值,这样就必然是不相交的,如果找到了相同的hash值,则是在两个字符串中各出现了一次,在原串中出现两次。但是这么做会TLE。
于是,就通过后缀自动机中的len来计数。
最上面讲过了len[u]-len[fa[u]]+1 表示能够接受的不同串的个数,那么就是规定了一个上届和下届,如果我们把上届或者下届的意义改了,就可以计算我们需要的串的个数了。
在这题中,我们将串拆成两部分,第一部分塞进后缀自动机,用后一部分来匹配,匹配每一个节点能够匹配的最远距离mi[u]mi[u],那么讲状态u接受的字符串区间分成了两部分(len[fa[u]],mi[u]]和(mi[u],len[u]]( len[fa[u]],mi[u] ]和(mi[u],len[u]],很明显,前面是后半部分能够匹配的那部分串,后面是不能匹配的。那么我们需要的就是将每个节点的(len[fa[u]],mi[u]]( len[fa[u]],mi[u] ]部分加起来就行了。

同时还要注意的是,从u→fa[u]u\rightarrow fa[u]累加的情况。fail指针,指向了一个能够表示当前状态表示的所有字符串的最长公共后缀的结点。简单说,就是fail指针指向了一个v,从v到root表示的串是u到root表示的串中的一部分,然后要求的是最长。
那么也就是说,如果str在u这个状态匹配了mi[u]mi[u],那么str很可能在fa[u]也匹配了mi[u]mi[u](当然有些情况下,mi[u]mi[u]会超过len[fa[u]],可以直接取min),所以必须要累加过去。

//      whn6325689
//      Mr.Phoebe
//      http://blog.csdn.net/u013007900
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
#include <functional>
#include <numeric>
#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;#define eps 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LLINF 1LL<<62
#define speed std::ios::sync_with_stdio(false);typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;
typedef vector<int> vi;#define CLR(x,y) memset(x,y,sizeof(x))
#define CPY(x,y) memcpy(x,y,sizeof(x))
#define clr(a,x,size) memset(a,x,sizeof(a[0])*(size))
#define cpy(a,x,size) memcpy(a,x,sizeof(a[0])*(size))#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define lowbit(x) (x&(-x))#define MID(x,y) (x+((y-x)>>1))
#define ls (idx<<1)
#define rs (idx<<1|1)
#define lson ls,l,mid
#define rson rs,mid+1,r
#define root 1,1,ntemplate<class T>
inline bool read(T &n)
{T x = 0, tmp = 1;char c = getchar();while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();if(c == EOF) return false;if(c == '-') c = getchar(), tmp = -1;while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();n = x*tmp;return true;
}
template <class T>
inline void write(T n)
{if(n < 0){putchar('-');n = -n;}int len = 0,data[20];while(n){data[len++] = n%10;n /= 10;}if(!len) data[len++] = 0;while(len--) putchar(data[len]+48);
}
//-----------------------------------const int MAXN=2010;
const int MAC=26;struct SAM
{int len[MAXN],next[MAXN][MAC],fa[MAXN],L,last;int sum[MAXN],topo[MAXN];int mi[MAXN];SAM(){init();}void init(){L=0;last=newnode(0,-1);}int newnode(int l,int pre){fa[L]=pre;mi[L]=0;for(int i=0;i<MAC;i++)  next[L][i]=-1;len[L]=l;return L++;}void add(int x){int pre=last,now=newnode(len[pre]+1,-1);last=now;while(~pre && next[pre][x]==-1){next[pre][x]=now;pre=fa[pre];}if(pre==-1) fa[now]=0;else{int bro=next[pre][x];if(len[bro]==len[pre]+1)    fa[now]=bro;else{int fail=newnode(len[pre]+1,fa[bro]);memcpy(next[fail],next[bro],sizeof next[bro]);fa[bro]=fa[now]=fail;while(~pre && next[pre][x]==bro){next[pre][x]=fail;pre=fa[pre];}}}}void toposort(){CLR(sum,0);for(int i=0;i<L;i++)    sum[len[i]]++;for(int i=1;i<L;i++)    sum[i]+=sum[i-1];for(int i=0;i<L;i++)    topo[--sum[len[i]]]=i;}void query(char *S){int u=0,x,cnt=0;for(char *sp=S;*sp;sp++){x=*sp-'a';if(~next[u][x]){u=next[u][x];mi[u]=max(mi[u],++cnt);}else{while(~u && next[u][x]==-1)u=fa[u];if(u==-1)cnt=0,u=0;else{cnt=len[u]+1;u=next[u][x];mi[u]=max(mi[u],cnt);}}}}int build(){int ans=0;toposort();for(int i=L-1;i>=0;i--){int u=topo[i];if(~fa[u])mi[fa[u]]=max(mi[fa[u]],mi[u]);}for(int i=0;i<L;i++){mi[i]=min(mi[i],len[i]);if(~fa[i] && mi[i]>len[fa[i]])ans+=(mi[i]-len[fa[i]]);}return ans;}
}T;char str[MAXN];int main()
{while(scanf("%s",str)!=EOF && str[0]!='#'){int le=strlen(str);T.init();for(int i=1;i<le;i++){T.add(str[i-1]-'a');T.query(str+i);}printf("%d\n",T.build());}return 0;
}

在HDU 4416中
求的是A这个字符串,有多少各子串在BiB_i中没有出现过。
上一题求的是出现过的,这一题求的是没有出现过的。
同样的分析,最终将区间分成两部分(len[fa[u]],mi[u]]和(mi[u],len[u]]( len[fa[u]],mi[u] ]和(mi[u],len[u]],很明显,前面是出现过的,后面是没出现过的,于是我们需要将后面那部分加起来就行了。

//      whn6325689
//      Mr.Phoebe
//      http://blog.csdn.net/u013007900
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>
#include <functional>
#include <numeric>
#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;#define eps 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LLINF 1LL<<62
#define speed std::ios::sync_with_stdio(false);typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef complex<ld> point;
typedef pair<int, int> pii;
typedef pair<pii, int> piii;
typedef vector<int> vi;#define CLR(x,y) memset(x,y,sizeof(x))
#define CPY(x,y) memcpy(x,y,sizeof(x))
#define clr(a,x,size) memset(a,x,sizeof(a[0])*(size))
#define cpy(a,x,size) memcpy(a,x,sizeof(a[0])*(size))#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define lowbit(x) (x&(-x))#define MID(x,y) (x+((y-x)>>1))
#define ls (idx<<1)
#define rs (idx<<1|1)
#define lson ls,l,mid
#define rson rs,mid+1,r
#define root 1,1,ntemplate<class T>
inline bool read(T &n)
{T x = 0, tmp = 1;char c = getchar();while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();if(c == EOF) return false;if(c == '-') c = getchar(), tmp = -1;while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();n = x*tmp;return true;
}
template <class T>
inline void write(T n)
{if(n < 0){putchar('-');n = -n;}int len = 0,data[20];while(n){data[len++] = n%10;n /= 10;}if(!len) data[len++] = 0;while(len--) putchar(data[len]+48);
}
//-----------------------------------const int MAXN=(100010<<1);
const int MAC=26;struct SAM
{int len[MAXN],next[MAXN][MAC],fa[MAXN],L,last;int mi[MAXN];SAM(){init();}void init(){L=last=0;newnode(0,-1);}int newnode(int l,int pre){fa[L]=pre;for(int i=0; i<MAC; i++)    next[L][i]=-1;len[L]=l;mi[L]=0;return L++;}void build(const char* p){int le=strlen(p);for(int i=0; i<le; i++)add(p[i]-'a');toposort();}void add(int x){int pre=last,now=newnode(len[pre]+1,-1);last=now;while(~pre && next[pre][x]==-1){next[pre][x]=now;pre=fa[pre];}if(pre==-1) fa[now]=0;else{int bro=next[pre][x];if(len[bro]==len[pre]+1)    fa[now]=bro;else{int fail=newnode(len[pre]+1,fa[bro]);for(int i=0; i<MAC; i++)    next[fail][i]=next[bro][i];fa[bro]=fa[now]=fail;while(~pre && next[pre][x]==bro){next[pre][x]=fail;pre=fa[pre];}}}}int sum[MAXN],topo[MAXN];void toposort(){CLR(sum,0);for(int i=0; i<L; i++)  sum[len[i]]++;for(int i=1; i<L; i++)  sum[i]+=sum[i-1];for(int i=0; i<L; i++)  topo[--sum[len[i]]]=i;}void query(const char* S){int u=0,x,cnt=0;for(const char* sp=S; *sp; sp++){x=*sp-'a';if(~next[u][x]){u=next[u][x];mi[u]=max(mi[u],++cnt);}else{while(~u && next[u][x]==-1)u=fa[u];if(u==-1)cnt=0,u=0;else{cnt=len[u]+1;u=next[u][x];mi[u]=max(mi[u],cnt);}}}}
} T;char str[MAXN];
int q,k;int main()
{int t,cas=1;scanf("%d",&t);while(t--){scanf("%d",&q);T.init();scanf("%s",str);T.build(str);while(q--){scanf("%s",str);T.query(str);}for(int i=T.L-1; i>=1; i--){int u=T.topo[i];if(T.mi[u]>0)T.mi[T.fa[u]]=max(T.mi[T.fa[u]],T.mi[u]);elseT.mi[u]=T.len[T.fa[u]];}ll ans=0;for(int i=1; i<T.L; i++)if(T.len[i]>T.mi[i])ans+=T.len[i]-T.mi[i];printf("Case %d: %lld\n",cas++,ans);}return 0;
}

HDU 3518 HDU 4416【后缀自动机len的使用】相关推荐

  1. HDU 4416 (后缀自动机)

    HDU 4416 Good Article Good sentence Problem : 给一个串S,和一些串T,询问S中有多少个子串没有在T中出现. Solution :首先对所有的T串建立后缀自 ...

  2. HDU 4416 后缀自动机

    题意:多组样例t,每个样例一个数n,接下来一个字符串 T ,n个字符串S,问T的子串有多少没有在S中出现 解:先将n个字符串加入后缀自动机,统计子串个数 ans,再把T加入后缀自动机,统计字符串个数a ...

  3. 不在B中的A的子串数量 HDU - 4416 (后缀自动机模板题目)

    题目: 给定一个字符串a,又给定一系列b字符串,求字符串a的子串不在b中出现的个数. 题解: 先将所有的查询串放入后缀自动机(每次将sam.last=1)(算出所有子串个数) 然后将母串放入后缀自动机 ...

  4. hdu 6194string string string 后缀自动机

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6194 查询原串中出现次数等于k次的子串数量.需要用到基数排序. 构造完后缀自动机之后将节点按照maxl ...

  5. HDU - 3518 Boring counting(后缀数组)

    题目链接:点击查看 题目大意:给出一个字符串,问有多少个子串出现了两次以上,计算时彼此不能覆盖 题目分析:因为数据范围比较小,我们可以直接暴力,枚举子串的长度,利用height数组的性质将后缀分为不同 ...

  6. HDU - 4416 Good Article Good sentence(广义后缀自动机/后缀自动机)

    题目链接:点击查看 题目大意:给出一个字符串 s ,再给出 n 个字符串 t ,现在问字符串 s 中有多少个不同的子串满足不是 t1 ~ tn 中任意一个字符串的子串 题目分析:第一次接触这样的题目, ...

  7. HDU多校4 - 6988 Display Substring(后缀自动机+二分)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的字符串 sss,每个字母都有一个权值,现在要求所有本质不同子串中权值和第 kkk 大的权值 题目分析:如果没有本质不同,那有一个很简单的二分套二 ...

  8. HDU - 4641 K-string(后缀自动机)

    题目链接:点击查看 题目大意:给出一个字符串 s ,规定 K-string 为字符串 s 中出现次数大于等于 k 次的字串,现在有 m 次操作,每次操作有两种: 1 ch:在字符串 s 后面添加字符 ...

  9. HDU 6194 后缀自动机

    后缀自动机求K次出现的子串的个数: #include <iostream> #include<cstdio> #include<algorithm> #includ ...

最新文章

  1. 关于云计算 你所知道的可能不是真的
  2. rpm包安装和卸载,rpm查询,yum工具详解,yum仓库搭建
  3. android9.0首发机型,安卓9.0正式发布,EMUI开启多款机型同步内部测试
  4. MySQL—修改、删除数据(一)
  5. 论林耐斯-Linux系统的重要性
  6. 终于收到HacktoberFest的奖品啦
  7. 【Python CheckiO 题解】Count Consecutive Summers
  8. 一图流“系列——Ruby vSphere Console命令脑图
  9. 【KITTI】KITTI数据集简介(一) — 激光雷达数据
  10. 从零开始写一个Jison解析器(3/10):良好的开端是成功的一半——《政治学》 (亚里士多德)
  11. 实现Comparable接口和Comparator接口
  12. iOS 渐变色 以及 镂空效果的实现(Mask的妙用)以及镂空文字的实现
  13. 正则表达式限定输入数字
  14. java验证xml格式是否正确的是_java判断文件是否为xml格式的方法
  15. 西西吹雪:从程序员到项目经理(一)
  16. 在java中 哈希表会经常出现哈希碰撞吗
  17. 【Nginx 流量控制】控制一秒处理多少请求
  18. u盘服务器安装win7系统安装教程,服务器u盘安装win7系统
  19. XP系统最高支持IE几?
  20. 【手机充电器仿真】2021-12-24

热门文章

  1. 【无标题】关于DBC文件的格式解析(DBC文件系列其二)
  2. 详解 P沟道mos管与N沟道mos管
  3. 如何在 Vim 中用换行符替换字符
  4. 一文万字带你入门智能路由器OpenWrt系统,并在虚拟中安装配置OpenWrt
  5. 【漏洞复现】永恒之蓝 MS17-010 远程溢出漏洞(CVE-2017-0143)
  6. 2022起重机司机(限桥式起重机)特种作业证考试题库及在线模拟考试
  7. pcs增加mysql资源_pcs命令配置示例(详细版)
  8. 2022杭电多校八 1011-Stormwind(贪心)
  9. 济南大学计算机专硕考研真题,济南大学考研真题各专业汇总
  10. 2018焦作ICPC E. Resistors in Parallel(打表+大数)