http://acm.hdu.edu.cn/showproblem.php?pid=5745
这题好劲爆啊。dp容易想,但是要bitset优化,就想不到了。
先放一个tle的dp。复杂度O(n * m)的
第一个串,记作str[],第二个记作sub[]
思路就是,设dp[i][j][k]表示,匹配了sub的前i个,以str的第j个结尾,然后sub[i]有三种状态,0表示不变化,1表示和前一个,2表示和后一个。
那么以求dp[i][j][0]为列
因为需要的是判断str的第j个结尾是否和sub的前i个完全匹配。
那么,要使得dp[i][j][0]为true,必然需要前i - 1个和j - 1个匹配成功。就是要递推过来。
那么dp[i][j][0] = (dp[i - 1][j - 1][0] || dp[i - 1][j - 1][1]) && (str[j] == sub[i])
其他的类似啦。
可以滚动下数组。
不清0的话,直接用DFN代替即可。这样的复杂度就是O(n * m),没有常数。但是还是TLE.
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> #include <bitset> const int maxn = 1e5 + 20; char str[maxn], sub[maxn]; int dp[2][maxn][3]; int DFN; char ans[maxn]; void work() { DFN++; int lenstr, lensub; scanf("%d%d", &lenstr, &lensub); scanf("%s", str + 1); scanf("%s", sub + 1); // dp[0][0][0] = DFN; for (int i = 0; i <= lenstr; ++i) dp[0][i][0] = DFN; int now = 0; for (int i = 1; i <= lensub; ++i) { now = !now; for (int j = 1; j <= lenstr; ++j) { // if ((dp[i - 1][j - 1][0] || dp[i - 1][j - 1][1]) && str[j] == sub[i]) { // dp[i][j][0] = true; // } // if (dp[i - 1][j - 1][2] && str[j] == sub[i - 1]) { // dp[i][j][1] = true; // } // if ((dp[i - 1][j - 1][0] || dp[i - 1][j - 1][1]) && sub[i + 1] == str[j]) { // dp[i][j][2] = true; // } if ((dp[!now][j - 1][0] == DFN || dp[!now][j - 1][1] == DFN) && str[j] == sub[i]) { dp[now][j][0] = DFN + 1; } if (dp[!now][j - 1][2] == DFN && str[j] == sub[i - 1]) { dp[now][j][1] = DFN + 1; } if ((dp[!now][j - 1][0] == DFN || dp[!now][j - 1][1] == DFN) && str[j] == sub[i + 1]) { dp[now][j][2] = DFN + 1; } } DFN++; } for (int i = 1; i <= lenstr; ++i) { ans[i] = '0'; if (dp[now][i][0] == DFN || dp[now][i][1] == DFN || dp[now][i][2] == DFN) { // printf("1"); ans[i - lensub + 1] = '1'; } } ans[lenstr + 1] = '