zoukankan      html  css  js  c++  java
  • hdu 5745 La Vie en rose DP + bitset优化

    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] = '';
        printf("%s
    ", ans + 1);
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        int t;
        scanf("%d", &t);
        while (t--) work();
        return 0;
    }
    View Code

    然后百度了一个bitset的优化。

    考虑用bitset<1e5> dp[5000][k]

    dp[i][k]

    表示,处理了sub的前i个,当前sub的状态是k,然后匹配整个str串的结果就是dp[i][k],因为dp[i][k]是一个长度为1e5的01串嘛。也就是dp[i][k]就是匹配好的结果了。

    那么,要快速计算dp[i][0],只需要(dp[i - 1][0] | dp[i - 1][1]) << 1

    比如前2个匹配好的结果是"10"和"11"然后匹配成的第三位,就是"011",关键看看第三位,是1,也就是上面的dp[i - 1][j - 1][k] = true的意思。就是前面的匹配好了,但是还要看看str[j]和sub[i]的相等情况。

    要想这一位是true,必然要这一位和sub对应相等。但是我们一次要算出整一个结果,而不是一个一个地算,那么,预处理个pos[26]的bitset就可以,&一下,就是要对应位置是1的,才是true。

    3478ms,我是卡过去的

    后来一直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;
    bitset<maxn> dp[2][3];
    char str[maxn], sub[maxn];
    bitset<maxn>pos[26];
    
    void init() {
        for (int i = 0; i <= 1; ++i) {
            for (int j = 0; j <= 2; ++j) {
                dp[i][j].reset();
            }
        }
        for (int i = 0; i < 26; ++i) pos[i].reset();
    }
    char ans[maxn];
    void work() {
        init();
        int lenstr, lensub;
        scanf("%d%d", &lenstr, &lensub);
        scanf("%s%s", str + 1, sub + 1);
        for (int i = 1; i <= lenstr; ++i) {
            pos[str[i] - 'a'][i] = 1;
        }
        dp[0][0] = pos[sub[1] - 'a'];
        if (lensub >= 2) dp[0][2] = pos[sub[2] - 'a'];
        int now = 0;
        for (int i = 2; i <= lensub; ++i) {
            now = !now;
            dp[now][0] = ((dp[!now][0] | dp[!now][1]) << 1) & pos[sub[i] - 'a'];
            dp[now][1] = (dp[!now][2] << 1) & pos[sub[i - 1] - 'a'];
            if (i < lensub) {
                dp[now][2] = ((dp[!now][0] | dp[!now][1]) << 1) & pos[sub[i + 1] - 'a'];
            }
        }
        for (int i = 1; i <= lenstr; ++i) {
            if (i + lensub - 1 > lenstr) {
                ans[i] = '0';
            } else {
                if (dp[now][0][i + lensub - 1] || dp[now][1][i + lensub - 1]) {
                    ans[i] = '1';
                } else ans[i] = '0';
            }
        }
        ans[lenstr + 1] = '';
        printf("%s
    ", ans + 1);
    //    printf("
    ");
    }
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        int t;
        scanf("%d", &t);
        while (t--) work();
        return 0;
    }
    View Code
  • 相关阅读:
    以后面试官再问你三次握手和四次挥手,直接把这一篇文章丢给他
    聊聊面试中常问的GC机制
    四面快手、终拿Offer,想告诉你的一些事情
    深入浅出14个Java并发容器
    Dubbo 在 K8s 下的思考
    一文带你深入浅出Spring 事务原理
    如何高效选择一款消息队列?
    当面试官要你介绍一下MQ时,该怎么回答?
    淘宝双11促销背后采用什么架构技术来实现网站的负载均衡
    Android 更改按钮样式 Button Styles
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6263832.html
Copyright © 2011-2022 走看看