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;
}