1. 程式人生 > >【bzoj4641】基因改造 特殊匹配條件的KMP

【bzoj4641】基因改造 特殊匹配條件的KMP

ceo ring 字符 復雜度 digi fread cst ati 復雜

題目描述

如果兩個長度相等的字符串,如果存在一種字符的一一映射,使得第一個字符串的所有字符經過映射後與第二個字符串相同,那麽就稱它們“匹配”。現在給出兩個串,求第一個字符串所有長度等於第二個字符串的長度的子串中與第二個字符串“匹配”的所有子串的位置。

輸入

輸入文件的第一行包含兩個正整數case和C,分別表示數據組數和人類智慧脫氧核苷酸的種數。 接下來3*case行,每三行表示一組數據: 第一行一個正整數N和M,表示人類智慧DNA片段S和TB智慧DNA片段T的長度。 第二行N個正整數,表示人類智慧DNA片段S。 第三行M個正整數,表示TB智慧DNA片段T。 對於所有數據數據,case=3, n,m,C<=1000000

輸出

對於每組數據: 第一行一個正整數tot,表示"萌萌噠人類基因片段"的個數。 接下來一行tot個用空格隔開的正整數pos,表示"萌萌噠人類基因片段"開頭所在的位置。要求從小到大輸出每個pos。

樣例輸入

3 3
6 3
1 2 1 2 3 2
3 1 3
6 3
1 2 1 2 1 2
3 1 3
6 3
1 1 2 1 2 1
3 1 3

樣例輸出

3
1 2 4
4
1 2 3 4
3
2 3 4


題解

特殊匹配條件的KMP

本題和 【bzoj2384】[Ceoi2011]Match 類似。

考慮什麽樣的兩個串是“匹配”的:每個位置數的上一次出現位置與其距離相同。

那麽可以把每個位置的權值當作該數上一次出現的位置與其的距離,然後跑KMP即可。

這裏需要註意的一點是,在求next數組和匹配時,如果一個位置的上一次出現位置與其距離大於當前串長(這種情況在求next計算後半部分,以及匹配時的母串中出現),那麽應當視為該數沒有出現過,需要特殊處理。

時間復雜度 $O(n)$

#include <cstdio>
#include <cctype>
#include <cstring>
#define N 1000010
int pa[N] , pb[N] , pos[N] , next[N] , ans[N];
inline char nc()
{
	static char buf[100000] , *p1 , *p2;
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 100000 , stdin) , p1 == p2) ? EOF : *p1 ++ ;
}
inline int read()
{
	int ret = 0; char ch = nc();
	while(!isdigit(ch)) ch = nc();
	while(isdigit(ch)) ret = ((ret + (ret << 2)) << 1) + (ch ^ ‘0‘) , ch = nc();
	return ret;
}
int main()
{
	int T = read();
	read();
	while(T -- )
	{
		int n = read() , m = read() , i , j , x , tot = 0;
		memset(pos , -1 , sizeof(pos));
		for(i = 0 ; i < n ; i ++ ) x = read() , pa[i] = (~pos[x] ? i - pos[x] : -1) , pos[x] = i;
		memset(pos , -1 , sizeof(pos));
		for(i = 0 ; i < m ; i ++ ) x = read() , pb[i] = (~pos[x] ? i - pos[x] : -1) , pos[x] = i;
		next[0] = -1;
		for(i = 1 , j = -1 ; i <= m ; i ++ )
		{
			while(~j && pb[i - 1] != pb[j] && !(pb[i - 1] > j && pb[j] == -1)) j = next[j];
			next[i] = ++j;
		}
		for(i = j = 0 ; i < n ; i ++ )
		{
			while(~j && pa[i] != pb[j] && !(pa[i] > j && pb[j] == -1)) j = next[j];
			if(++j == m) ans[++tot] = i - m + 2 , j = next[j];
		}
		printf("%d\n" , tot);
		for(i = 1 ; i <= tot ; i ++ ) printf("%d " , ans[i]);
		printf("\n");
	}
	return 0;
}

【bzoj4641】基因改造 特殊匹配條件的KMP