【模板】字符串

哈希 字符串匹配 https://loj.ac/problem/103

#include<cstdio>//#include<iostream>
#include<cstring>
#define ULL unsigned long long//using namespace std;
char s[1001000],st[1001000];
ULL pow[1001000],sum[1001000],b=97;
int main()
{
	pow[0]=1;
	for(int i=1;i<=1000000;i++) pow[i]=pow[i-1]*b;
	int n,m;
	scanf("%s %s",st+1,s+1);
	n=strlen(st+1),m=strlen(s+1);
	sum[0]=0;//系数递减  s1*b^m + s2*b^(m-1) + s3*b^(m-2) +…… 
	for(int i=1;i<=n;i++) sum[i]=sum[i-1]*b+(ULL)(st[i]-'A'+1); 
	ULL ss=0;  for(int i=1;i<=m;i++) ss=ss*b+(ULL)(s[i]-'A'+1);
	int ans=0;  
	for(int l=0;l<=n-m;l++)
	{//越接近后面,指数越小,所以应把前面的剪掉 
		if(ss==sum[l+m]-sum[l]*pow[m]) ans++;//cout<<ss<<' '<<sum[l+n]<<endl;
	}printf("%d",ans);
	return 0;
} 
KMP 字符串匹配 https://loj.ac/problem/10043

#include<cstdio>
#include<cstring>
char a[1010],b[1010];
int next[1010]; 
int main()
{
	while(1)
	{
		scanf("%s",a+1); int la=strlen(a+1);  if(a[1]=='#' && la==1) break;
		scanf("%s",b+1); int lb=strlen(b+1); 		
		next[1]=0; //b[next[j]]=a[i],b[next[1]]不一定等于a[1],作为一个起点b[next[1]+1]就是b[1] 
		for(int i=1,j=0;i<lb;i++)
		{	//必须隔一位才能首尾呼应 
			while(j>0 && b[i+1]!=b[j+1]) j=next[j]; 
			if(a[i+1]==b[j+1]) j++;
			next[i+1]=j;
		}int i=0,j=0,ans=0;
		while(i<la){		
			while(j>0 && a[i+1]!=b[j+1]) j=next[j]; 
			if(a[i+1]==b[j+1]){j++; 
				if(j==lb) { ans++; j=0; }
			}i++;
		}printf("%d\n",ans);	
	}
	return 0;
}/* acaacaaa  回到0:相当于无法继承前面,(而b[1]本来为1,但一定要不继承,不然会死循环) 
	0011234  不同,'a'!='c',退到前缀尾a,再找前缀中可以继承的公共前后缀 
	前缀覆盖为后缀 ;  next[]既是位置又是长度 */
字典树 查找最长由给出单词拼接的前缀 https://loj.ac/problem/10053

#include<cstdio>
#include<cstring>
char st[101],t[4001000];
struct node{int son[27];bool end;}tr[1500010];   //27^10
int len=0,n,l;
void bt(){
	int now=0,s;
	for(int i=1;i<=l;i++){
		s=st[i]-'a';
		if(tr[now].son[s]==0) tr[now].son[s]=++len; 
		now=tr[now].son[s];
	}tr[now].end=true;	
}
bool flag[4001000]; 
void find()
{/* 需注意:whatis ,字典中有what,wh  
做法,遇到end不返回,标记为true */
	int now=0,s,ans=0;
	for(int i=1;i<=l;i++) flag[i]=false;
	flag[0]=true;
	for(int i=0;i<=l;i++){
		if(flag[i]) ans=i; else continue;
		for(int j=i+1;j<=l;j++){//跟着上一次匹配的词继续
			s=t[j]-'a';	
			now=tr[now].son[s];
			if(now==0) break;
			if(tr[now].end) flag[j]=true;	
		}
	}printf("%d\n",ans);
}
int main()
{
	int n,m;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%s",st+1);
		l=strlen(st+1); bt();
	}
	for(int i=1;i<=m;i++){
		scanf("%s",t+1); 
		l=strlen(t+1); find();
	}
	return 0;
}
01字典树 求树上最大异或和    树上路径异或和=x到根异或和^y到根异或和
https://loj.ac/problem/10056

#include<cstdio>
#include<cstring>
struct node{int son[2],end;}tr[3200000]; //最多数量*最大位   
int er[32],len=0;
int maxx(int x,int y) { return x>y?x:y; }
void m_er()	{ er[0]=1; 	for(int i=1;i<=30;i++) er[i]=er[i-1]*2; }
//==================================================================
int first[100100],blen=0;
struct bian{int y,c,gg;}b[200100];
void ins(int x,int y,int c){
	b[++blen].y=y;b[blen].c=c;
	b[blen].gg=first[x];
	first[x]=blen;
}
int d[100100];
void dfs(int x,int fa){//统计各点到根的异或和
	for(int i=first[x];i>0;i=b[i].gg){
		int y=b[i].y;
		if(y!=fa){
			d[y]=d[x]^b[i].c;
			dfs(y,x);
		}
	}
}//===================================================01字典树 
void bt(int x){
	int now=0,z,o=x;
	for(int i=30;i>=0;i--){ 	
		z=o/er[i];
		if(z==1) o-=er[i];
		if(tr[now].son[z]==0) tr[now].son[z]=++len;
		now=tr[now].son[z];
	}tr[now].end=x;
}
int find(int x){
	int now=0,z,o=x;
	for(int i=30;i>=0;i--){
		z=o/er[i];
		if(z==1) o-=er[i];
		if(tr[now].son[1-z]) z=1-z;
		now=tr[now].son[z];
	}return tr[now].end^x;
}//=============================================================
int main()
{
	m_er();
	int x,y,c,ans=0,n;
	scanf("%d",&n); 
	for(int i=1;i<n;i++){
		scanf("%d %d %d",&x,&y,&c); 
		ins(x,y,c);ins(y,x,c);
	}d[1]=0;dfs(1,0);//下同例2 
	for(int i=1;i<=n;i++) bt(d[i]);
	for(int i=1;i<=n;i++) ans=maxx(ans,find(d[i]));
	printf("%d",ans);
	return 0;
}
AC自动机 文章匹配多单词 https://loj.ac/problem/10057

#include<cstdio>
#include<cstring>
char s[60],st[1000100];
struct tree{int son[26],end;}tr[500010];//50*10000
int len=1,fail[500010];
int t,n,m;
void bt(int l){//字典树
	int now=0,c;
	for(int i=1;i<=l;i++){
		c=s[i]-'a';
		if(tr[now].son[c]==0) tr[now].son[c]=++len;
		now=tr[now].son[c];
	}tr[now].end++;
}
void bfs_fail(){
	int li[501000],tou=1,wei=1;
	int s,now=0;fail[0]=0;
	for(int i=0;i<26;i++){
		if(tr[now].son[i]!=0){
			fail[tr[now].son[i]]=0;
			li[wei++]=tr[now].son[i];
		}
	}
	while(tou!=wei){
		now=li[tou];
		for(int i=0;i<26;i++){
			s=tr[now].son[i];
			if(s!=0)
			{//printf("%d %c %d\n",s,i+'a',tr[fail[now]].son[i]);
				fail[s]=tr[fail[now]].son[i];
				li[wei++]=s;
			}else tr[now].son[i]=tr[fail[now]].son[i];
		}tou++;//优化:不用每个儿子都跳至fail[now] 
	}
}
int find(){
	int now=0,ans=0,z;
	for(int i=1;i<=m;i++){
		z=now=tr[now].son[st[i]-'a'];//now顺下 
		while(z>1 && tr[z].end>-1){
			if(tr[z].end) ans+=tr[z].end,tr[z].end=-1;
			z=fail[z];//对于同一个字母,可能是某个结尾 
		}
	}return ans;
}
int main()
{
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%s",s+1);
			bt(strlen(s+1));//建字典树 
		}
		bfs_fail();
		scanf("%s",st+1);m=strlen(st+1);
		printf("%d\n",find());
		for(int i=1;i<=500000;i++){
			tr[i].end=0;for(int j=0;j<26;j++) tr[i].son[j]=0;	
		}
	}
	return 0;
} 
//后缀数组

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值