字符串算法整理(upd:2022.1.21)

字符串

by AmanoKumiko

1.Hash

适用范围:灵活


2.可持久化Trie

https://oi-wiki.org/ds/persistent-trie/

struct Trie{
	int ch[M][2],last[N],cnt,val[M];
	void insert(int x,int v){
		int nx=last[x],ny=last[x-1];
		fd(p,29,0){
			int g=v&(1<<p)?1:0;
			val[nx]=val[ny]+1;
			if(!ch[nx][g])ch[nx][g]=++cnt;
			ch[nx][!g]=ch[ny][!g];
			ny=ch[ny][g];nx=ch[nx][g];
		}
		val[nx]=val[ny]+1;
	}
	int query(int x,int y,int v){
		int res=0;
		x=last[x-1];y=last[y];
		fd(p,29,0){
			int g=v&(1<<p)?0:1;
			if(val[ch[y][g]]-val[ch[x][g]]){res|=1<<p;x=ch[x][g];y=ch[y][g];}
			else x=ch[x][!g],y=ch[y][!g];
		}
		return res;
	}
	void build(int x){if(!last[x])last[x]=++cnt;}
}t;

Problems

【JZOJ5382】数列

适用范围:一般为异或题

PS:上为常见的可持久化01Trie


3.Manacher

https://oi-wiki.org/string/manacher/

F(i,1,n){
	d[i]=i>r?1:min(d[(r-i)+l],r-i);
	while(s[i-d[i]]==s[i+d[i]]&&i-d[i]>=1&&i+d[i]<=n)d[i]++;
	if(i+d[i]>r)l=i-d[i],r=i+d[i];
}

适用范围:最长回文串,回文串个数

Problems:

【国集】最长双回文串

【GDKOI2021】回文

PS:回文题一般也可用字符串哈希求解


4.AC自动机

https://www.cnblogs.com/hyfhaha/p/10802604.html

fail:拥有相同后缀的前缀的深度最大的点

struct ACM{
	int son[P][26],fail[P],p;
	void insert(int x){
		int u=1;
		F(j,1,len[x])!son[u][s[x][j]-'a']?u=son[u][s[x][j]-'a']=++p:u=son[u][s[x][j]-'a'];
	}
	void build(){
		F(i,0,25)son[0][i]=1;q.push(1);
		while(!q.empty()){
			int u=q.front();q.pop();
			F(i,0,25){
				int v=son[u][i],Fail=fail[u];
				if(!v){son[u][i]=son[Fail][i];continue;}
				fail[v]=son[Fail][i];q.push(v);
			}
		}
	}
}t;

适用范围:匹配

Problems:

【JSOI2012】玄武密码

【JZOJ3472】匹配

【HNOI2006】最短母串

【TJOI2013】单词

【POI2000】病毒

【JSOI2007】文本生成器

PS:

遇到AC自动机+dp时,不应该只是用在AC自动机上dp的思想设状态,要结合别的思想,状压、容斥、正难则反…

遍历AC自动机时,不能粗暴枚举,而应该按照bfs序


5.SA

https://oi-wiki.org/string/sa/#_13

struct SA{
	int n,sa[N],rk[N],fir[N],sec[N],t[N],height[N];
	void get(){
		n=strlen(s+1);
		memset(t,0,sizeof(t));
		F(i,1,n)t[fir[i]=s[i]]++;
		F(i,1,max(122,n))t[i]+=t[i-1];
		Fd(i,n,1)sa[t[fir[i]]--]=i;
		for(int len=1;len<n;len<<=1){
			int cnt=0;
			F(i,n-len+1,n)sec[++cnt]=i;
			F(i,1,n)if(sa[i]>len)sec[++cnt]=sa[i]-len;
			memset(t,0,sizeof(t));
			F(i,1,n)t[fir[i]]++;
			F(i,1,max(122,n))t[i]+=t[i-1];
			Fd(i,n,1)sa[t[fir[sec[i]]]--]=sec[i],sec[i]=0;
			swap(fir,sec);
			fir[sa[1]]=cnt=1;
			F(i,2,n)fir[sa[i]]=(sec[sa[i]]==sec[sa[i-1]]&&sec[sa[i]+len]==sec[sa[i-1]+len]?cnt:++cnt);
			if(cnt==n)break;
		}
		F(i,1,n)rk[sa[i]]=i;
		int h=0;
		F(i,1,n){
			if(rk[i]==1)continue;
			if(h)h--;
			while(s[sa[rk[i]-1]+h]==s[i+h])h++;
			height[rk[i]]=h;
		}
	}
}t;

适用范围:统计不同子串个数,LCS,LCP,多次出现的子串

Problems:

【AHOI2013】差异

【HAOI2016】找相同字符

【HEOI2016/TJOI2016】字符串


6.PAM

https://www.cnblogs.com/nianheng/p/9814530.html

struct PAM{
	int son[N][26],len[N],s[N],fail[N],tot,last,n;
	LL size[N];
	int getfail(int p,int x){while(ch[p]!=ch[p-len[x]-1])x=fail[x];return x;}
	void build(){
		scanf("%s",ch+1);
		n=strlen(ch+1);
		last=tot=fail[0]=fail[1]=1;
		len[1]=-1;
		F(i,1,n){
			int now=getfail(i,last);
			if(!son[now][ch[i]-'A']){
				tot++;
				fail[tot]=son[getfail(i,fail[now])][ch[i]-'A'];
				son[now][ch[i]-'A']=tot;
				len[tot]=len[now]+2;
			}
			size[son[now][ch[i]-'A']]++;
			last=son[now][ch[i]-'A'];
		}
		Fd(i,tot,2)size[fail[i]]+=size[i];
	}
}P;

适用范围:统计回文串个数,回文串出现次数

Problems:

【JSOI2013】快乐的JYY

【JZOJ4752】字符串合成


7.SAM

https://oi-wiki.org/string/sam/

struct SAM{
	int ch[N][26],len[N],link[N],tot,rt,last;
	void build(){
		scanf("%s",s+1);
		n=strlen(s+1);
		rt=tot=last=1;
		F(i,1,n){
			int u=++tot,v=last,pos=s[i]-'a';
			for(;v&&!ch[v][pos];v=link[v])ch[v][pos]=u,len[u]=max(len[u],len[v]+1);
			if(!v)link[u]=rt;
			else if(len[v]+1==len[ch[v][pos]])link[u]=ch[v][pos];
			else{
				int Old=ch[v][pos],clone=++tot;
				len[clone]=len[v]+1;
				F(j,0,25)ch[clone][j]=ch[Old][j];
				link[clone]=link[Old];
				link[Old]=link[u]=clone;
				for(;v&&ch[v][pos]==Old;v=link[v])ch[v][pos]=clone;
			}
		}
	}
}S;

适用范围:统计字串个数,统计字串长度和,匹配(出现)类问题

Problems:

【GDKOI2014】基因模式

【SDOI2016】生成魔咒

posted @ 2021-01-30 19:21  冰雾  阅读(96)  评论(0编辑  收藏  举报