2018北京ICPC H. Approximate Matching(AC自动机+DP)

 

H : Approximate Matching

时间限制: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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值