unsigned int BKDRHash(char *str)
{
unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
unsigned int hash = 0;
while (*str)
{
hash = hash * seed + (*str++);
}
return (hash & 0x7FFFFFFF);
}
将每一个字符串设成一个数。
我们也可以用hash来判断两个子串是否相等。
#include<stdio.h>
#include<string.h>
#define seed 131
char s[10];
long long hash[10];
long long bit[10];
long long calc(int l,int r)
{
return hash[r]-hash[l-1]*bit[r-l+1];//是bit[r-l+1]不是bit[l-1]!!!!!!!!!!!!!!!!!
}
int main()
{
scanf("%s",s);
int n=strlen(s);
for(int i=0;i<n;i++)
{
hash[i+1]=hash[i]*seed+s[i];
}
bit[0]=1;
for (int a=1;a<=n;a++)
bit[a]=bit[a-1]*seed;
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
printf("%lld ",calc(i,j));
}
printf("\n");
}
}
让我们来模拟一下:
样例:abab
hash[ 1 ] = a;
hash[ 2 ] = a*seed+b;
hash[ 3 ] = a*seed^2+b*seed+a;
hash[ 4 ] = a*seed^3+b*seed^2+a*seed+b;
bit[1]=seed, bit[2]=seed^2,bit[3]=seed^3,bit[4]=seed^4;
cal(1, 2)=a*seed+b;
cal(3, 4)=hash[ 4 ]-hash[2]*bit[2]=a*seed+b;
^-^更快^-^
hash判断回文串
scanf("%s",s);
len=strlen(s);
ll l=0,r=0,e=1;
for(int i=0;i<len;i++)
{
l=l*seed+s[i];
r=r+s[i]*e;
e*=seed;
if(l==r)
{
yes;
}
}
挂链法
将字符串转化成整数后对一个值取模,在余数下面挂上这个数。这样可以查找这个字符串是否出现过,或以字符串为结点建图。
struct dot
{
int to,next;
ll val;
}hash[100050];
int headhash[100050];
int cchash;
void addhash(ll x)//类似建边,从余数指向这个数
{
int loc=x%mm;
hash[cchash].to=loc;
hash[cchash].val=x;
hash[cchash].next=headhash[loc];
headhash[loc]=cchash++;
}
int find(char s[])
{
ll tot=s[0]-'A';
for(int i=1;i<strlen(s);i++)
{
tot=tot*seed+s[i]-'a';
}
int loc=tot%mm;
for(int i=headhash[loc];i!=-1;i=hash[i].next)
{
if(hash[i].val==tot)
{
return i;
}
}
addhash(tot);
return cchash-1;
}
……………………………………………………………………………………………………………………………………………………………………………………………………………
bzoj2795
[Poi2012]A Horrible Poem
1、若循环节长度为len ,则[st,to-len]与[st+len,to]相同;
2、len是字符串总长度的约数;
所以枚举字符串长度的质因数k,将这个字符串分成k份,判断把每一份当做循环节是否成立。
把找到的循环节再不断分解,直到不能再分为止。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#define seed 131
using namespace std;
typedef unsigned long long ll;
ll l;
char s[500100];
ll q;
ll len,st,to;
vector <pair <int ,int> >pri[500100];
bool vis[500100];
void init()//预处理每个 长度 的质因数及其个数,放在pri里。
{
for(ll i=2;i<=l;i++)
{
if(!vis[i])
{
for(ll j=i;j<=l;j+=i)
{
ll h=0;
ll v=j;
while(v%i==0)
{
v/=i;
h++;
}
pri[j].push_back(make_pair(i,h));
vis[j]=true;
}
}
}
}
ll hash[500100];
ll bit[500100];
ll cal(ll f,ll t)
{
return hash[t]-hash[f-1]*bit[t-f+1];
}
int main()
{
// freopen("str.in","r",stdin);
// freopen("str.out","w",stdout);
scanf("%llu",&l);
scanf("%s",s+1);
for(ll i=1;i<=l;i++)//字符串hash
{
hash[i]=hash[i-1]*seed+s[i];
}
bit[0]=1;
for(ll i=1;i<=l;i++)
{
bit[i]=bit[i-1]*seed;
}
init();
scanf("%llu",&q);
while(q--)
{
scanf("%llu %llu",&st,&to);
len=to-st+1;
ll ans=len;
for(int i=0;i<(int)pri[len].size();i++)
{
ll k=pri[len][i].first;
ll p=pri[len][i].second;
ll mul=1;
for(ll j=1;j<=p;j++)
{
mul*=k;
}
while(p--)
{
ll xun=len/mul;
if(cal(st,to-xun)==cal(st+xun,to))
{
ans/=mul;
break;
}
mul/=k;
}
}
printf("%llu\n",ans);
}
}