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编辑  收藏  举报

导航