字符串hash,bzoj2795[Poi2012]A Horrible Poem

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章