HDU 4416 Good Article Good sentence(后缀自动机)

【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=4416

【题目大意】

  给出一个字符串,然后,给出一个字符串集合,问在该字符串中出现,且不在字符串集合中出现的子串总数。

【题解】

  将集合中所有的子串在自动机上跑,保存匹配到的位置的最长匹配,
  用于在parent树上计算每个位置的最长匹配,对于一个位置,
  如果不存在匹配,那么他对答案的贡献就是其value值,
  如果存在匹配且匹配长度小于其长度那么取其差作为答案的贡献。最后输出即可。

【代码】

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=200005;
char s[N];
struct sam{
	  int p,q,np,nq,cnt,last,a[N][26],l[N],f[N];
	  sam(){cnt=0;last=++cnt;}
	  int val(int c){return l[c]-l[f[c]];}
	  void init(){
	      cnt=0;last=++cnt;
	      memset(a,0,sizeof(a));
	      memset(l,0,sizeof(l));
	      memset(f,0,sizeof(f));
	      memset(b,0,sizeof(b));
	      memset(u,0,sizeof(u));
	  }
	  void extend(int c){
		    p=last;np=last=++cnt;l[np]=l[p]+1;
		    while(!a[p][c]&&p)a[p][c]=np,p=f[p];
		    if(!p)f[np]=1;
		    else{
			      q=a[p][c];
			      if(l[p]+1==l[q])f[np]=q;
			      else{
				        nq=++cnt;l[nq]=l[p]+1;
				        memcpy(a[nq],a[q],sizeof(a[q]));
				        f[nq]=f[q]; f[np]=f[q]=nq;
				        while(a[p][c]==q)a[p][c]=nq,p=f[p];
			      }
		    }
	  }int b[N],x[N],n;
	  void build(){
		    scanf("%s",s+1);
		    int len=strlen(s+1);n=len;
		    for(int i=1;i<=len;i++)extend(s[i]-‘a‘);
		    for(int i=1;i<=cnt;i++)b[l[i]]++;
		    for(int i=1;i<=len;i++)b[i]+=b[i-1];
		    for(int i=1;i<=cnt;i++)x[b[l[i]]--]=i;
	  }int u[N];
	  void doit(){
		    scanf("%s",s+1);
		    int p=1,len=strlen(s+1),tmp=0;
		    for(int i=1;i<=len;i++){
			      int c=s[i]-‘a‘;
			      if(a[p][c])p=a[p][c],tmp++,u[p]=max(u[p],tmp);
			      else{
				        while(p&&!a[p][c])p=f[p];
				        if(!p)p=1,tmp=0;
				        else tmp=l[p]+1,p=a[p][c],u[p]=max(u[p],tmp);
			      }
		    }
		}
		void solve(){
		    long long ans=0;
		    for(int i=cnt;i;i--){
		        if(u[x[i]]){
		            u[f[x[i]]]=max(u[x[i]],u[f[x[i]]]);
		            if(u[x[i]]<l[x[i]])ans+=l[x[i]]-u[x[i]];
		        }else ans+=val(x[i]);
		    }printf("%I64d\n",ans);
		}
}sam;
int T,n,cas=1;
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        sam.init();
        sam.build();
        for(int i=1;i<=n;i++)sam.doit();
        printf("Case %d: ",cas++);
        sam.solve();
    }return 0;
}

  

时间: 2024-10-10 22:31:42

HDU 4416 Good Article Good sentence(后缀自动机)的相关文章

hdu 4416 Good Article Good sentence(后缀自动机)

题目链接:hdu 4416 Good Article Good sentence 题意: 给你一个串A和n个串B,问你A有多少个子串不是这n个B的子串. 题解: 将A串建立后缀自动机,对于每个B串都拿去匹配一下,并记录后缀自动机中每个节点的最大匹配长度. 然后拓扑排序,更新每个节点的fail节点.最后对于每个节点的贡献就是ml[i]-max(is[i],mx[f[i]]) (is[i]是该节点的最大匹配长度) 1 #include<bits/stdc++.h> 2 #define F(i,a,

hdu 4416 Good Article Good sentence (后缀数组)

题目大意: 给出一个A串和很多个B串,求出A中有多少个子串,是所有的B中没有出现的. 思路分析: 后缀数组的作用很容易的求出来整个串中不同的子串个数. 现在要求的是A中不同的,且在B中没有出现过的. 先把AB 串全部连接,跑一遍suffix array.然后求出有多少个不同的子串. 然后再单独用B 串跑 suffix array.再求出单独在B 中有多少个不同的 子串. 然后结果就是 ans1 - ans2 ... 需要注意的问题就是,连接的时候需要把每一个串后面加一个特殊符.但是求不同串的时候

hdu 4416 Good Article Good sentence(后缀数组&amp;思维)

Good Article Good sentence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2308    Accepted Submission(s): 649 Problem Description In middle school, teachers used to encourage us to pick up pre

[hdu 4416]Good Article Good sentence

最近几天一直在做有关后缀自动机的题目 感觉似乎对后缀自动机越来越了解了呢!喵~ 这题还是让我受益颇多的,首先搞一个后缀自动机是妥妥的了 可是搞完之后呢? 我们来观察 step 这个变量,每个节点的 step 是从根节点到此节点所经过的最长步数 那么也就是以该点为结尾的最长的后缀长度 如何统计不被 Bi 串包含的子串呢? 其实很简单,维护每个节点所能匹配的最长的字符串长度 然后 节点->step-max(该节点所能匹配的最长的字符串长度, 节点->fail->step) 就是答案了 因为

hdu 5343 MZL&#39;s Circle Zhou(后缀自动机)

题目链接:hdu 5343 MZL's Circle Zhou 题意: 给你两个串A,B,问从A,B中选子串x,y,问x+y可以组成多少个不同的串,x和y可以为空. 题解: 贴一个官方的题解 1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=(a);i<=(b);++i) 4 using namespace std; 5 using ll=unsi

HDOJ 题目4416 Good Article Good sentence(后缀数组求a串子串在b串中不出现的种类数)

-每周六晚的BestCoder(有米!) Good Article Good sentence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2784    Accepted Submission(s): 785 Problem Description In middle school, teachers used to encour

HDOJ 4416 Good Article Good sentence

题解转自:http://blog.csdn.net/dyx404514/article/details/8807440 2012杭州网络赛的一道题,后缀数组后缀自己主动机都行吧. 题目大意:给一个字符串S和一系列字符串T1~Tn,问在S中有多少个不同子串满足它不是T1~Tn中随意一个字符串的子串. 思路:我们先构造S的后缀自己主动机,然后将每个Ti在S的SAM上做匹配,类似于LCS,在S中的每个状态记录一个变量deep,表示T1~Tn,在该状态能匹配的最大长度是多少,将每个Ti匹配完之后,我们将

HDU 6194 string string string(后缀自动机)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3238 [题目大意] 给出一个字符串求其出现恰好k次的子串数量 [题解] 对串建立AC自动机,所有right值为k的节点的value值的和就是答案 [代码] #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=200010; cha

Good Article Good sentence HDU - 4416 (后缀自动机)

Good Article Good sentence \[ Time Limit: 3000 ms\quad Memory Limit: 32768 kB \] 题意 给出一个 \(S\) 串,在给出 \(n\) 个 \(T\) 串,求出 \(S\) 串中有多少子串没有在任意一个 \(T\) 串中出现过 思路 \(\quad\) 首先可以对 \(S\) 串构建后缀自动机,然后在插入 \(n\) 个 \(T\) 串,每两个串之间用 \(27\) 隔开,然后可以求出这个自动机上每个节点出现的最左位置