NOIP模板复习——字符串

哈希

直接用 unsigned long long,让它自然溢出(对 2 64 2^{64} 取模)就行了

对一个字符串哈希( a n s ans 是哈希值, b a s e base 是基数, l l 是字符串长度, s i s_i 是第 i i 个字符):

#define ull unsigned long long
ull Hash()
{
	ull ans=0;
	for(int i=0;i<l;++i)
	  ans=ans*base+s[i];
	return ans;
}

当然,为了使正确性更高,可以用两个哈希或者甚至更多个哈希

KMP

A 是模式串,B 是匹配串,nA 的长度,mB 的长度

输出为 BA 中所有能够匹配上的第一个位置(下标都是从 1 1 开始)

void init()
{
	int i,j=0;
	for(i=2;i<=m;++i)
	{
		while(j&&B[i]!=B[j+1])  j=nxt[j];
		if(B[i]==B[j+1])  ++j;
		nxt[i]=j;
	}
}
void work()
{
	int i,j=0;
	for(i=1;i<=n;++i)
	{
		while(j&&A[i]!=B[j+1])  j=nxt[j];
		if(A[i]==B[j+1])  ++j;
		if(j==m)
		{
			j=nxt[j];
			printf("%d\n",i-m+1);
		}
	}
}

Trie

以找前缀的数量为例吧

存储

struct Trie
{
	int son[26];
	int num;
}a[N];

插入 t t 是节点编号, s s 是要插入的字符串)

void Insert()
{
	int l,i,p=0;
	l=strlen(s);
	for(i=0;i<l;++i)
	{
		if(a[p].son[s[i]-'a']==0)
		  a[p].son[s[i]-'a']=++t;
		p=a[p].son[s[i]-'a'];
		a[p].num++;
	}
}

查询

int find()
{
	int l,i,p=0;
	l=strlen(s);
	for(i=0;i<l;++i)
	{
		if(a[p].son[s[i]-'a']==0)
		  return 0;
		p=a[p].son[s[i]-'a'];
	}
	return a[p].num;
}

如果直接 memset 清零的话可能会比较慢,可以边做的时候边清空,这样会快一点

Manacher

int R[N<<1];
char Old[N],New[N<<1];
int init()
{
	int i,l,j=2;
	scanf("%s",Old);
	l=strlen(Old);
	New[0]='$';
	New[1]='#';
	for(i=0;i<l;++i)
	{
		New[j++]=Old[i];
		New[j++]='#';
	}
	New[j]='\0';
	return j;
}
int manacher()
{
	int i,l,p,m=0,Max=0;
	l=init();
	for(i=1;i<l;++i)
	{
		if(i>=m)  R[i]=1;
		else  R[i]=min(R[2*p-i],m-i);
		while(New[i-R[i]]==New[i+R[i]])  R[i]++;
		if(m<i+R[i])  {m=i+R[i];p=i;}
		Max=max(Max,R[i]-1);
	}
	return Max;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/83821245
今日推荐