Problem Description
Professor Zhang would like to solve the multiple pattern matching problem, but he only has only one pattern string p=p1p2…pm. So, he wants to generate as many as possible pattern strings from p using the following method:
- select some indices i1,i2,…,ik such that 1≤i1 < i2 < … < ik < |p| and |ij−ij+1| >1 for all 1 ≤ j < k.
- swap pij and pij+1 for all 1≤j≤k.
Now, for a given a string s=s1s2…sn, Professor Zhang wants to find all occurrences of all the generated patterns in s.
Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
The first line contains two integers n and m (1≤n≤105,1≤m≤min{5000,n}) – the length of s and p.
The second line contains the string s and the third line contains the string p. Both the strings consist of only lowercase English letters.
Output
For each test case, output a binary string of length n. The i-th character is “1” if and only if the substring sisi+1…si+m−1 is one of the generated patterns.
网上搜了好多题解,全是sb的O(n*m)。。表示很无语。。赛上没敢写暴力。
这题其实是很好的一个学bitset暴力压位的题。。让我再次体会到二进制的魔法。。
这个题的转移方程很简单
设dpi,j,k表示s串匹配到i位置,t串匹配到j位置t串末尾与前面交换0,不交换1,与后面交换2的情况
dpi,j,0=dpi−1,j−1,2 and si==tj−1
dpi,j,1=(dpi−1,j−1,1 or dpi−1,j−1,0) and si==tj−1
dpi,j,2=(dpi−1,j−1,1 or dpi−1,j−1,0) and si==tj+1
显然暴力会超时(没超时只是出题人挂数据的时候挂错了。。)
看下转移方程可以发现,
i,j
转移的时候是同步减少的。并且dp存的值是布尔型。
此类状态要自然而然的想到,把第一维或者第二维状压,以当前位1表示可以匹配,0表示不能匹配。然后转移的时候把之前的状态左移一位(增加一位,具体增加多少看转移状态而定)并且和预处理出来的26个字母匹配状态取and。
具体操作见代码
//
// Created by Running Photon
// Copyright (c) 2015 Running Photon. All rights reserved.
//
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <bitset>
#include <queue>
#include <string>
#include <sstream>
#include <set>
#include <vector>
#include <stack>
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x,begin())
#define ll long long
#define CLR(x) memset(x, 0, sizeof x)
using namespace std;
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 1e5 + 10;
const int maxv = 5e3 + 10;
const double eps = 1e-9;
char s[maxn], t[maxv];
bitset <maxn> dp[2][3];
bitset <maxn> sta[26];
int main() {
#ifdef LOCAL
freopen("C:\\Users\\Administrator\\Desktop\\in.txt", "r", stdin);
// freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout);
#endif
// ios_base::sync_with_stdio(0);
int lens, lent;
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &lens, &lent);
scanf("%s%s", s, t);
for(int i = 0; i < 26; i++) {
sta[i].reset();
}
for(int j = 0; j < lens; j++) {
sta[s[j] - 'a'][j] = 1;
}
for(int i = 0; i < 2; i++) {
for(int k = 0; k < 3; k++) {
dp[i][k].reset();
}
}
//1表示t[j]不交换,0表示t[j]与前面的交换,2表示t[j]与后面的交换
dp[0][1] = sta[t[0]-'a'];
if(lent > 1)
dp[0][2] = sta[t[1]-'a'];
int cur = 0;
for(int i = 1; i < lent; i++) {
cur ^= 1;
dp[cur][1] = ((dp[cur^1][0] | dp[cur^1][1]) << 1) & sta[t[i]-'a'];
dp[cur][0] = ((dp[cur^1][2]) << 1) & sta[t[i-1]-'a'];
if(i < lent - 1)
dp[cur][2] = ((dp[cur^1][0] | dp[cur^1][1]) << 1) & sta[t[i+1]-'a'];
}
for(int i = 0; i < lens; i++) {
if(dp[cur][0][i+lent-1] || dp[cur][1][i+lent-1])
printf("1");
else printf("0");
}
puts("");
}
return 0;
}