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