HIHOCODER 1465 後綴自動機五·重複旋律8 後綴自動機

更好的閱讀體驗 Press Here

Problem

傳送門 >ω<

題目大意:

給定模式串 ssnn 個匹配串 stristr_i
求每個匹配串的循環同構能夠匹配的子串總數

Solution

求循環同構的匹配,首先第一步應該是將匹配串倍長,再進行匹配,這樣就能得到匹配串所有循環同構

但是發現一個匹配串的循環同構可能會相同,而不能計算重複的匹配

如何實現?

對於每個匹配串的每個位置,都能求出模式串中的最長匹配前綴
如果匹配串某個位置的匹配長度超過了原匹配串長度,就說明以該位置爲結尾字符的串一定能夠與模式串匹配

所以找到包含原串長度的狀態,並且標記即可(防止重複)

代碼

#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
int read() {
	int ans = 0 , flag = 1;
	char ch = getchar();
	while(ch > '9' || ch < '0') {if(ch == '-') flag = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {ans = ans * 10 + ch - '0'; ch = getchar();}
	return ans * flag;
}
char s[N];
struct SAM {
	int ch[N << 1][26] , fa[N << 1] , l[N << 1] , siz[N << 1];
	int bac[N] , T[N  << 1];
	int vis[N << 1];
	int cnt , last;
	void ins(int c) {
		int x = last , nx = ++ cnt; last = nx;
		l[nx] = l[x] + 1; siz[nx] = 1;
		for(; x && !ch[x][c] ; x = fa[x]) ch[x][c] = nx;
		if(!x) fa[nx] = 1;
		else {
			int y = ch[x][c];
			if(l[y] == l[x] + 1) fa[nx] = y;
			else {
				int ny = ++ cnt; l[ny] = l[x] + 1;
				memcpy(ch[ny] , ch[y] , sizeof(ch[y]));
				fa[ny] = fa[y]; fa[y] = fa[nx] = ny;
				for(; x && ch[x][c] == y ; x = fa[x]) ch[x][c] = ny;
			}
		}
	} 
	void insert(char *s) {
		cnt = last = 1;
		int len = strlen(s);
		for(int i = 0 ; i < len ; ++ i) ins(s[i] - 'a');

		for(int i = 1 ; i <= cnt ; ++ i) ++ bac[l[i]];
		for(int i = 1 ; i <= len ; ++ i) bac[i] += bac[i - 1];
		for(int i = 1 ; i <= cnt ; ++ i) T[bac[l[i]] --] = i;
		for(int i = cnt ; i ; -- i) siz[fa[T[i]]] += siz[T[i]];
	}
	void cal(char * s , int qwe) {
		int n = strlen(s) , c  , m = n * 2 - 1;
		int x = 1 , lenth = 0 , ans = 0;
		for(int i = 0 , h = 0 ; i < n * 2 - 1 ; ++ i , ++ h) {
			if(h >= n) h -= n;
			c = s[h] - 'a';
			while(x && !ch[x][c]) {x = fa[x]; lenth = l[x];}
			if(ch[x][c]) {x = ch[x][c]; ++ lenth;}
			else {x = 1; lenth = 0;}
			if(lenth > n) while(l[fa[x]] >= n) {x = fa[x]; lenth = l[x];}
			if(lenth >= n && vis[x] != qwe) {vis[x] = qwe; ans += siz[x];}
		}
		printf("%d\n" , ans);
	}
}sam;
int main() {
	scanf("%s" , s);
	sam.insert(s);
	int t = read();
	for(int i = 1 ; i <= t ; ++ i) {
		scanf("%s" , s);
		sam.cal(s , i);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章