1. 程式人生 > 實用技巧 >牛客網 P15253 白兔的字串 (字串雜湊)

牛客網 P15253 白兔的字串 (字串雜湊)

題目連結:https://ac.nowcoder.com/acm/problem/15253

詢問迴圈同構是否相同,那就將原串所有的迴圈同構串的雜湊值表示出來,
迴圈同構相當於是一個環,所以化環為鏈,長度加倍,然後依次處理即可

\(H[i]\) 表示字首 \(i\) 的雜湊值,則字串 \([l,r]\) 的雜湊值即為 \(H[r] - H[l - 1] * P[r - l + 1]\)
其中 \(p[i]\) 表示 \(base\)\(i\) 次冪

對每個詢問串遍歷檢查即可

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

const int maxn = 2000010;
const ull base = 131;
 
int n, L;
ull p[maxn], f[maxn];

char A[maxn], C[maxn];
char S[maxn];

ull v[maxn];
int tot = 0; 

inline void solve(){
	scanf("%s", S + 1);
	int len = strlen(S + 1);
	for(int i = 1 ; i <= len ; ++i){
		f[i] = f[i - 1] * base + S[i] - 'a' + 1;
	} 
	
	ll ans = 0;
	for(int i = 1; i + L - 1 <= len ; ++i){
		ull val = f[i + L - 1] - f[i - 1] * p[L];
		int p = lower_bound(v + 1, v + 1 + tot, val) - v;
		if(v[p] == val) ++ans;
	}
	cout << ans << endl;
}

ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }

int main(){
	p[0] = 1;
	for(int i = 1 ; i <= 2000000 ; ++i){ p[i] = p[i - 1] * base; }
	scanf("%s", A + 1);

	n = read();
	
	L = strlen(A + 1);
	for(int i = 1 ; i < L ; ++i) A[i + L] = A[i];
	
	for(int i = 1 ; i <= L + L ; ++i){
		f[i] = f[i - 1] * base  + A[i] - 'a' + 1;
	} 
	
	for(int i = 1 ; i <= L ; ++i){
		ull val = f[i + L - 1] - f[i - 1] * p[L];
		v[++tot] = val;
	}
	
	sort(v + 1, v + 1 + tot);
	
	for(int i = 1 ; i <= n ; ++i){
		solve();
	}
	
	return 0;
}