1. 程式人生 > >tokitsukaze and Similar String(字串雜湊)

tokitsukaze and Similar String(字串雜湊)

題目連結:

tokitsukaze and Similar String

 

題意:

tokitsukaze獲得了一個長度為n (1≤n≤10^5),由a-z小寫字母組成的字串。

我們定義兩個字串是相似的,當且僅當能通過多次以下操作,使得兩個字串相等。並且把需要操作的最小次數,稱為兩個字串的相似度。

操作是這樣的:選擇一個字串,把字串的每個字母都替換為字母表上的下一個字母,同時,我們認為z的下一個字母為a,比如選擇"acdz",操作一次後變為"bdea"。

現在tokitsukaze從字串中任取兩個子串,她想知道它們是不是相似的,如果它們相似,請輸出相似度,如果它們不相似,請輸出-1。

 

思路:

字串雜湊。

預處理26種變化的Hash表,每次詢問用Hash表來判斷子串是否相等。若 x 的第 i 種變化與 y 相等,ans=min(i,26-i) 。

 

Code:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;

const int MAX = 1e5+10;
const ll mod = 1e9+7;
const ull P = 131;

int n,q;
char s[MAX];
ull Hash[MAX][30];
ull pw[MAX];

ull get(int l,int r,int t){
    return Hash[r][t]-Hash[l-1][t]*pw[r-l+1];
}

int main()
{
    scanf("%d%s%d",&n,s+1,&q);
    pw[0]=1;
    for(int i=1;i<=n;i++){
        for(int j=0;j<26;j++){
            Hash[i][j]=Hash[i-1][j]*P+(s[i]-'a'+1+j)%26;
            if((s[i]-'a'+1+j)%26==0)    Hash[i][j]+=26;
        }
        pw[i]=pw[i-1]*P;
    }
    while(q--){
        int x,y,len;
        scanf("%d%d%d",&x,&y,&len);
        int t = ((s[y]-'a'+1+26)-(s[x]-'a'+1))%26;
        if(get(x,x+len-1,t)==get(y,y+len-1,0)){
            printf("%d\n",min(t,26-t));
        }
        else{
            printf("-1\n");
        }
    }
    return 0;
}