hdu5745La Vie en rose

来源:互联网 发布:movielens数据集 编辑:程序博客网 时间:2024/04/30 05:35

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5745

题意:给定一个母串s和一个子串p。问s中有多少个位置可以匹配p,可以不完全匹配,p字符串中的每个位置的字符最多可以变动一次(不变的,与前面的字符交换,与后面的字符交换)。

分析:做多校学姿势。xg的题解解释得很好,但是对于我这种没写过这种优化的人来说还是要看代码学习一遍,我说下我的理解吧。首先xg列出了dp方程:dp[i][j][0]=dp[i-1][j-1][2]&&s[i]==p[j-1]、dp[i][j][1]=(dp[i-1][j-1][0]||dp[i-1][j-1][1])&&s[i]==p[j]、dp[i][j][2]=(dp[i-1][j-1][0]||dp[i-1][j-1][1])&&s[i]==p[j+1]。我们先遍历p的1~m个字符然后用bitset来表示有遍历到当前p[i]时上一层有哪些位置的i是匹配到了前i-1个字符,然后根据当前字符是谁直接去找哪些位置是合法的来更新当前层。这样的话我们就能一层一层的得到1~n的哪些位置是合法的。重点是预处理出26个字符在哪些位置出现过然后用bitset存下来以便能直接&出当前层哪些位置是合法的,还不懂的话看看代码吧。O(n*m/w)。PS:XG增强了数据,减小了时间,变成了3.5s。我的程序过不了了。想过的人自己手写bitset卡卡常数吧。

代码:

#include<map>#include<set>#include<cmath>#include<queue>#include<bitset>#include<math.h>#include<vector>#include<string>#include<stdio.h>#include<cstring>#include<iostream>#include<algorithm>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;const int N=100010;const int mod=100000000;const int MOD1=1000000007;const int MOD2=1000000009;const double EPS=0.00000001;typedef long long ll;const ll MOD=1000000007;const int MAX=2000000010;const ll INF=1ll<<55;const double pi=acos(-1.0);typedef double db;typedef unsigned long long ull;char s[N],p[5010];bitset<N>w[30];bitset<N>dp[2][3];int main(){    int i,j,n,m,t,now,las;    scanf("%d", &t);    while (t--) {        scanf("%d%d", &n, &m);        scanf("%s%s", s+1, p+1);        for (i=0;i<26;i++) w[i].reset();        for (i=1;i<=n;i++) w[s[i]-'a'][i-1]=1;        now=las=1;dp[now][1].set();        dp[now][0].reset();dp[now][2].reset();        for (i=1;i<=m;i++) {            las=now;now^=1;            for (j=0;j<3;j++) dp[now][j].reset();            int pre=p[i-1]-'a',mid=p[i]-'a',suf=p[i+1]-'a';            if (i>1) dp[now][0]=(dp[las][2]&w[pre])<<1;            dp[now][1]=((dp[las][0]&w[mid])|(dp[las][1]&w[mid]))<<1;            if (i<m) dp[now][2]=((dp[las][0]&w[suf])|(dp[las][1]&w[suf]))<<1;        }        for (i=m;i<=n;i++)        if (dp[now][0][i]||dp[now][1][i]) printf("1");        else printf("0");        for (i=n+1;i<=n+m-1;i++) printf("0");printf("\n");    }    return 0;}


0 0