《雲頂之弈》11.10版德萊文主C陣容推薦
阿新 • • 發佈:2021-05-20
字串雜湊
作用:把一個字串變成一個很大的數字,可以用於判斷字串出現次數或兩個串是否相等
- 對陣列、變數的定義:
string s:字串 題目中要求s的hash
int base:一個較大質數 一般為233或23333 表示進位制 字串的雜湊值實際上是一個base進位制數
ull h[]:雜湊值(字首和) 使用ull是為了自然溢位 h[i]代表從字串的第1位到第i為的雜湊值
ull p[]:進位制陣列 p[i]=x表示字串的第i位轉換成數字時要乘以x
- 對進位制陣列、雜湊值陣列的處理:
p[0]=1;//無第0位,賦值為1是為了方便後續運算 for(int i=1;i<=n;i++) { p[i]=p[i-1]*base;//每一位的進位制都是前一位的進位制乘以base(左移一位) h[i]=h[i-1]*base+s[i];//前i位的雜湊值位前i-1位的雜湊值乘以進位制再加上當前位 }
舉例:
若輸入的s為"ABCDEFG"
h[1]("A")的值為'A'
h[2]("AB")的值為"A"×base+'B'
h[3]("ABC")的值為"AB"×base+'C'
以此類推
- 求子串的雜湊值
ull shash(int l,int r)//求s中從l到r的子串的雜湊值
return h[r]-h[l-1]*p[r-l+1];//從第1位到第r位的雜湊值-從第1位到第l位的前一位的雜湊值(乘以進位制類似於填零補位)
舉例:若輸入的s為"ABCDEFG" l為2,r為5
所以從l到r的子串為"BCDE"
h[r]為"ABCDE"
h[l-1]為"A"
如果直接相減肯定會有錯位 如下所示
ABCDE
- A
————
所以應該給"A"補位 要補的位數就是p陣列
p[r-l+1]=4
所以A應左移4位
ABCDE
-A
————
BCDE
最後所得的結果就是"BCDE"
- 例題
51nod 2619
#include<bits/stdc++.h> #define ull unsigned long long #define N 500010 using namespace std; ull p[N],h[N],flag; ull b=233; char s[N]; char ans[N]; int n; ull shash(int l,int r) { return h[r]-h[l-1]*p[r-l+1]; } bool findpos(int pos) { ull l,r; int mid=1+n>>1; if(pos==mid) { l=shash(1,mid-1); r=shash(mid+1,n); } else if(pos<mid) { l=shash(1,pos-1)*p[mid-pos]+shash(pos+1,mid); r=shash(mid+1,n); } else { l=shash(1,mid-1); r=shash(mid,pos-1)*p[n-pos]+shash(pos+1,n); } if(l==r&&flag!=l) { flag=l; if(pos<=mid) { for(int i=mid+1;i<=n;i++) ans[i-mid]=s[i]; } else { for(int i=1;i<mid;i++) ans[i]=s[i]; } return 1; } return 0; } int main() { cin>>n>>s+1; p[0]=1; for(int i=1;i<=n;i++) p[i]=p[i-1]*b,h[i]=h[i-1]*b+s[i]; if(n%2==0) { cout<<"NOT POSSIBLE"; return 0; } int cnt=0; for(int i=1;i<=n;i++) { cnt+=findpos(i); if(cnt>1) { cout<<"NOT UNIQUE"; return 0; } } if(cnt==0) cout<<"NOT POSSIBLE"; else cout<<ans+1; return 0; }