1. 程式人生 > >2018北京ICPC H. Approximate Matching(AC自動機+DP)

2018北京ICPC H. Approximate Matching(AC自動機+DP)

時間限制:1000ms,單點時限:1000ms,記憶體限制:512MB

描述

String matching, a common problem in DNA sequence analysis and text editing, is to find the occurrences of one certain string (called pattern) in a larger string (called text). In some cases, the pattern is not required to be exactly in the text, and minor differences are acceptable (due to possible typing mistakes). When given a pattern string and a text string, we say pattern P is approximately matched within text S, if there is a substring of S which is at most one letter different from P. Note that the length of this substring and the pattern must be identical. For example, pattern "abb" is approximately matched in text "babc" but not matched in "bbac".

It is easy to check if a pattern is approximately matched in a text. So your task is to count the number of all text strings of length m in which the given pattern can be approximately matched, and both of the patterns and texts are binary strings in order not to handle big integers.

輸入

The first line of input is a single integer T (1 ≤ T ≤ 666), the number of test cases. Each test case begins with a line of two integers n,m (1 ≤ n,m ≤ 40), denoting the length of pattern string and text string. Then a single line of binary string P follows, which denotes the pattern. Note that there will be at most 15 test cases in which n ≥ 16.

輸出

For each test case, output a single line with one integer, representing the answer.

樣例輸入

5
3 4
110
4 7
1011 
2 10
00
7 17
1001110
11 22
11101010001

樣例輸出

12
104
1023
72840
291544

題意:

給你一個n和m,之後給你一個長度為n的01串T,問有多少個長度為m的01串S滿足,T在最多修改一位的情況下可以成為S的子串

思路:

好像是道原題,不過原題是字母,這個是01串

暴力修改串T的每一位,將得到的新串加入AC自動機(別忘了可以不修改,原串也要加進去)

然後dp[i][j]表示只考慮前i個字元,其中最後一個字元落在自動機的j號節點上,不滿足條件的字串S個數

最後答案就是2^m-∑dp[m][i] (1<=i<=cnt,且i號節點不是某個單詞的末尾)

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
#define LL long long
#define mod 1000000007
queue<int> q;
char temp[106];
int n, str[106], cnt, tre[1805][4], End[1805], fail[1805];
LL dp[45][1805];
void Insert()
{
	int i, p = 1;
	for(i=1;i<=n;i++)
	{
		if(tre[p][str[i]]==0)
			tre[p][str[i]] = ++cnt;
		p = tre[p][str[i]];
	}
	End[p] = 1;
}
void ACmach()
{
	int now, i, p;
	q.push(1);
	fail[1] = 0;
	while(q.empty()==0)
	{
		now = q.front();
		q.pop();
		for(i=0;i<=1;i++)
		{
			if(tre[now][i]==0)
				continue;
			p = fail[now];
			while(tre[p][i]==0)
				p = fail[p];
			fail[tre[now][i]] = tre[p][i];
			if(End[tre[p][i]]==1)
				End[tre[now][i]] = 1;
			q.push(tre[now][i]);
		}
	}
}
int main(void)
{
	LL ans;
	int T, i, j, m, k, p;
	scanf("%d", &T);
	while(T--)
	{
		cnt = 1;
		scanf("%d%d%s", &n, &m, temp+1);
		for(i=1;i<=n;i++)
			str[i] = temp[i]-'0';
		memset(tre, 0, sizeof(tre));
		memset(End, 0, sizeof(End));
		memset(fail, 0, sizeof(fail));
		memset(dp, 0, sizeof(dp));
		tre[0][0] = tre[0][1] = 1;
		Insert();
		for(i=1;i<=n;i++)
		{
			str[i] ^= 1;
			Insert();
			str[i] ^= 1;
		}
		ACmach();
		dp[0][1] = 1;
		for(i=0;i<=m-1;i++)
		{
			for(j=1;j<=cnt;j++)
			{
				if(dp[i][j]==0 || End[j])
					continue;
				for(k=0;k<=1;k++)
				{
					p = j;
					while(tre[p][k]==0)
						p = fail[p];
					if(End[tre[p][k]])
						continue;
					dp[i+1][tre[p][k]] += dp[i][j];
				}
			}
		}
		ans = 1;
		for(i=1;i<=m;i++)
			ans = ans*2;
		for(i=1;i<=cnt;i++)
			ans -= dp[m][i];
		printf("%lld\n", ans);
	}
	return 0;
}