zoukankan      html  css  js  c++  java
  • 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("
    ");
        }
        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("
    ");
        }
        return 0;
    }
  • 相关阅读:
    在Linux下OpenCV的下载和编译
    安装GDB-ImageWatch ,在QT中查看图像
    linux下对qt编写的程序进行部署
    GOQTTemplate简单介绍
    寻找激光的交叉点
    基于opencv和QT的摄像头采集代码( GoQTtemplate3持续更新)
    图像处理工程师的要求研究
    如何将QT的pro图标修改的更显著一些
    快速阅读《QT5.9 c++开发指南》2
    小米盒子连接老式电脑显示器(VGA接口)
  • 原文地址:https://www.cnblogs.com/xiaochaoqun/p/7341580.html
Copyright © 2011-2022 走看看