hdu5745 La Vie en rose 巧妙地dp+bitset优化+滚动数组减少内存
/** 题目:hdu5745 La Vie en rose 链接:http://acm.hdu.edu.cn/showproblem.php?pid=5745 题意:题目给出的变换规则其实就是交换相邻元素, 并且每个元素最多交换一次. 思路: 那么一个O(nm)的dp其实十分显然, dp_{i,j,k} 表示匹配到s的第i个字符, p的第j个字符, j这一位的当前状态是k (0表示和前面交换, 1表示没有交换, 2表示和后面交换). 转移方程如下: 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]); 这个dp数组里面存的都是bool值, 可以考虑用bitset压缩这个dp数组中的第一维i, 然后滚动下第二维j, 就得到了O(N*M/W)的做法, 其中w是机器的字节长. */ /* 未用bitset优化前。 用一个滚动数组减少内存。 直接把枚举p串的那层循环放到第一层,然后滚动。 #include<iostream> #include<cstdio> #include<cstring> #include<bitset> #include<algorithm> #include<queue> using namespace std; typedef unsigned int ut; typedef long long LL; const int N = 1e5+1; const int M = 5e3+1; int dp[N][2][3]; char s[N], p[M]; int main() { int T; int n, m; cin>>T; while(T--) { scanf("%d%d",&n,&m); scanf("%s",s+1); int ls = strlen(s+1); scanf("%s",p+1); int lp = strlen(p+1); int d = 0; for(int j = 1; j <= lp; j++){ for(int i = 1; i <= ls; i++){ if(j==1){ dp[i][d][0] = 0; dp[i][d][1] = s[i]==p[j]; dp[i][d][2] = s[i]==p[j+1]; }else{ dp[i][d][0] = dp[i-1][d^1][2]&&(s[i]==p[j-1]); dp[i][d][1] = (dp[i-1][d^1][0]||dp[i-1][d^1][1])&&(s[i]==p[j]); dp[i][d][2] = (dp[i-1][d^1][0]||dp[i-1][d^1][1])&&(s[i]==p[j+1]); } } d^=1; } for(int i = m; i <= ls; i++){ printf("%d",dp[i][d^1][0]||dp[i][d^1][1]); } for(int i = 1; i < m; i++){ printf("0"); } printf("\n"); } return 0; } */ #include<iostream> #include<cstdio> #include<cstring> #include<bitset> #include<algorithm> #include<queue> using namespace std; typedef unsigned int ut; typedef long long LL; const int N = 1e5+1; const int M = 5e3+1; bitset<N> dp[2][3]; bitset<N> alp[30]; char s[N], p[M]; int main() { int T; int n, m; cin>>T; while(T--) { scanf("%d%d",&n,&m); scanf("%s",s+1); int ls = strlen(s+1); scanf("%s",p+1); int lp = strlen(p+1); for(int i = 0; i < 26; i++) alp[i].reset(); for(int i = 0; i < 2; i++){ for(int j = 0; j < 3; j++){ dp[i][j].reset(); } } for(int i = 1; i <= ls; i++){ alp[s[i]-'a'][i] = 1;///alp[i][j]表示i+'a'这个字符在s字符串的j位置出现过。 } dp[0][1] = alp[p[1]-'a'];///dp[i][j][k]表示p字符串的位置i与s字符串的位置k,j=0表示i-1位置,j=1表示i位置,j=2表示i+1位置。 ///所以dp[0][1]=alp[p[1]-'a'];和p字符串i位置相同的s字符串的k位置集合。 if(lp>=2) dp[0][2] = alp[p[2]-'a']; int d = 1; for(int j = 2; j <= lp; j++){ dp[d][0] = (dp[d^1][2]<<1)&alp[p[j-1]-'a']; dp[d][1] = ((dp[d^1][0]|dp[d^1][1])<<1)&alp[p[j]-'a']; if(j+1<=lp) dp[d][2] = ((dp[d^1][0]|dp[d^1][1])<<1)&alp[p[j+1]-'a']; d^=1; } for(int i = m; i <= ls; i++){ printf("%d",dp[d^1][0][i]||dp[d^1][1][i]); } for(int i = 1; i < m; i++){ printf("0"); } printf("\n"); } return 0; }
posted on 2017-08-10 21:42 hnust_accqx 阅读(119) 评论(0) 编辑 收藏 举报