1. 程式人生 > >NOIP模板複習——字串

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;
}