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.
Input
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.
Output
For each test case, output a single line with one integer, representing the answer.
题解:
近似匹配表示最多只能有一个字符不匹配,所以我们可以用源串s和它可能的近似匹配串都建立AC自动机,然后就是跑套路DP了-.-!
设dp[i][j]表示当前枚举到了第i个字符,在AC自动机上的j节点并且没有近似匹配的字符串的数量,因为题意求至少近似匹配一次,所以转换成反面会好做很多,求出没有近似匹配的字符串数量后,用2^m减去就好了
听说当时北京赛区5题能拿金(小声bb)
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 1005;
int nxt[MAXN][2],fail[MAXN],vis[MAXN],tot;
LL dp[MAXN][MAXN],qmi[50];
char s[MAXN];
inline void Init(){
for(int i=0;i<=tot;i++){
fail[i]=vis[i]=0;
for(int j=0;j<2;j++) nxt[i][j]=0;
}
tot=1;
}
inline void Insert(char *s){
int rt=0,len=strlen(s);
for(int i=0;i<len;i++){
if(!nxt[rt][s[i]-'0']) nxt[rt][s[i]-'0']=++tot;
rt=nxt[rt][s[i]-'0'];
}
vis[rt]=1;
}
inline void Build(){
queue<int> que;
for(int i=0;i<2;i++) if(nxt[0][i]) que.push(nxt[0][i]);
while(!que.empty()){
int u=que.front(); que.pop();
for(int i=0;i<2;i++){
if(nxt[u][i]) fail[nxt[u][i]]=nxt[fail[u]][i],que.push(nxt[u][i]);
else nxt[u][i]=nxt[fail[u]][i];
}
}
}
inline char change(char ch){ return (ch-'0')^1+'0'; }
int main(){
//freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
qmi[0]=1; for(int i=1;i<=45;i++) qmi[i]=qmi[i-1]*2;
int T; scanf("%d",&T);
while(T--){
Init();
int n,m; scanf("%d%d",&n,&m);
scanf("%s",s);
Insert(s);
for(int i=0;i<n;i++){
s[i]=change(s[i]);
Insert(s);
s[i]=change(s[i]);
}
Build();
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=1;i<=m;i++){
for(int j=0;j<=tot;j++){
if(vis[j]) continue;
for(int k=0;k<2;k++){
if(vis[nxt[j][k]]) continue;
dp[i][nxt[j][k]] += dp[i-1][j];
}
}
}
LL res = qmi[m];
for(int i=0;i<=tot;i++) res-=dp[m][i];
printf("%lld\n",res);
}
return 0;
}