『HDU 5745』La Vie en rose

题目链接:http://acm.hdu.edu.cn/submit.php?pid=5745

转载声明:http://blog.csdn.net/u012015746/article/details/51992281 (题解)
转载声明:http://blog.csdn.net/qll125596718/article/details/6901935 (bitset介绍)

题意:
这里写图片描述

个人感想:
我这种弱渣完全不会这种dp题,我怎么想我也觉得是kmp什么的匹配.那时比赛想到头都疼,本来想写个暴力试试能不能过,却被队友草了一脸…但是结果出来原来暴力都可以过.实在无语,非不让我尝试一下.好吧,回到正题.

首先呢这道题呢我也是借鉴上面的博客,还有问了一下大牛怎么回事我才懂了.我本来看了下题解,我觉得很容易啊,我写了个很朴素的DP,绝壁超时(可以滚到最后面看看咯…不过没啥用).因为都跑了15E次… 然后看了一下题解。。
Bitset!!(上面的链接可以了解下),这东西我也没说过,很神奇.不过大牛说暴力还比标程快…尼玛
好吧说说我的理解(大牛教我的…)吧.

假设样例
abcbacacb
abc

首先 把原串(org)每种字符的位置存下来(bitset存的二进制是从右到左存的!!请注意)
a:001010001;
b:100001010;
c:010100100;
为什么这样做呢?因为当pat匹配位置的时候,这是pat 当前i 对应字串能匹配的位置(不管pat后面的),这时我们就需要用他来承接上一次dp的结果并且相&,
假设我上一次的结果是 001010001;那么下一位b假设是在后面就是 01010010,相&(按道理)应该是01010010的答案才是对的啊…可是这两个相与就等于0!了,明显错的!所以每次得到的dp就必须往左移一位这样才能表示一种承接关系,因为既然pat串的 i-1位置适配了,那么下一个位置也要适配,往左相&一下才行,其他的还是按照dp的思想.
我是第一次做这种题目,所以也理解不够深,这是我遇到的情况了.

分析:DP+bitset.

AC代码:

/* Author:GavinjouElephant
 * Title:
 * Number:
 * main meanning:
 *
 *
 *
 */

//#define OUT
#include <iostream>
using namespace std;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <vector>
#include <set>
#include <cstdlib>
#include <map>
#include <queue>
#include <bitset>
//#include<initializer_list>
//#include <windows.h>
//#include <fstream>
//#include <conio.h>
#define MaxN 0x7fffffff
#define MinN -0x7fffffff
#define Clear(x) memset(x,0,sizeof(x))
const int INF=0x3f3f3f3f;
const int maxn=1e5+10;
const int maxm=5e3+10;
int N,M;
int T;
char org[maxn];
char pat[maxm];
bitset<maxn> w[26];
bitset<maxn> dp[2][3];
int ans[maxn];
int main()
{
#ifdef OUT
    freopen("coco.txt","r",stdin);
    freopen("lala.txt","w",stdout);
#endif
    scanf("%d",&T);
    while(T--)
    {

        scanf("%d%d",&N,&M);
        scanf("%s",org+1);
        scanf("%s",pat+1);
        for(int i=0;i<26;i++)w[i].reset();

        for(int i=1;i<=N;i++)
        {
            w[org[i]-'a'][i-1]=1;
        }
        dp[0][0].set();//没交换
        dp[0][1].reset();//和前面交换
        dp[0][2].reset();//和后面交换

        for(int i=1;i<=M;i++)
        {
            int cur=i&1;
            int last=(i-1)&1;

            int now=pat[i]-'a';
            int pre=pat[i-1]-'a';
            int sur=pat[i+1]-'a';
            dp[cur][0].reset();
            dp[cur][1].reset();
            dp[cur][2].reset();

            dp[cur][0]=((dp[last][1] | dp[last][0])&w[now])<<1;

            if(i>1) dp[cur][1]=((dp[last][2])&w[pre])<<1;

            if(i<M) dp[cur][2]=((dp[last][0] | dp[last][1])&w[sur])<<1;

        }
        memset(ans,0,sizeof(ans));
        for(int j=1;j<=N;j++)
        {
            if(dp[M&1][0][j] | dp[M&1][1][j])  ans[j-M+1]=1;
        }
        for(int i=1;i<=N;i++)
        {
            printf("%d",ans[i]);
        }
        printf("\n");

    }

    return 0;
}

个人代码:

/* Author:GavinjouElephant
 * Title:
 * Number:
 * main meanning:
 *
 *
 *
 */

//#define OUT
#include <iostream>
using namespace std;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <vector>
#include <set>
#include <cstdlib>
#include <map>
#include <queue>
//#include<initializer_list>
//#include <windows.h>
//#include <fstream>
//#include <conio.h>
#define MaxN 0x7fffffff
#define MinN -0x7fffffff
#define Clear(x) memset(x,0,sizeof(x))
const int INF=0x3f3f3f3f;
const int maxn=1e5+10;
int T;
int N,M;
char org[maxn];
char pat[maxn];
bool dp[maxn][3][3];
void init()
{
    memset(dp,false,sizeof(dp));
}
int main()
{
#ifdef OUT
    freopen("coco.txt","r",stdin);
    freopen("lala.txt","w",stdout);
#endif
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d%d",&N,&M);

        scanf("%s",org);
        scanf("%s",pat);

        for(int j=0;j<M;j++)
        {
            for(int i=0;i<N;i++)
            {
                 int J=j%3;

                 int lJ=J-1;
                 if(lJ<0)lJ+=3;

                 if(j==0)
                 {
                     dp[i][j][1]=(org[i]==pat[j]);
                     dp[i][j][2]=(org[i]==pat[j+1]);
                 }
                 else
                 {
                    if(i==0)continue;
                    dp[i][J][0]=dp[i-1][lJ][2]&&(org[i]==pat[j-1]);
                    dp[i][J][1]=(dp[i-1][lJ][1]||dp[i-1][lJ][0])&&(org[i]==pat[j]);
                    dp[i][J][2]=(dp[i-1][lJ][1]||dp[i-1][lJ][0])&&(org[i]==pat[j+1]);
                 }
            }

        }
        int J=(M-1)%3;
        for(int i=M-1;i<N;i++)
        {
            if(dp[i][J][0]||dp[i][J][1])printf("1");
            else printf("0");
        }
        for(int j=0;j<M-1;j++)
        {
             printf("0");
        }
        cout<<endl;
    }


    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值