Gym101466I DP 记忆化搜索

从前往后扫,对于既可以去A班,又可以去B班的人进行决策。

状态设计有两种姿势。

第一种姿势比较暴力&玄学:用dp[x][2][y][2]记录下,A班最后一位同学的id,这位同学有没有id比他更小的朋友。对B班也一样. 数组开不下,所以我们可以使用unordered map,但很不幸,这么做会MLE成智障,我们可以加一个小优化:发现了一个解后,直接结束输出Yes。

code

#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
const int N=100000+10;
int n,k,a[N],s[N];
bool chk1(int x) {
    vector<int> v;
    while(x) v.push_back(x%10), x/=10;
    for(int i=0;i<v.size();i++) 
        if (v[i] != v[v.size()-1-i])
            return 0;
    return 1;
}
bool chk2(int x) {
    while(x) {
        if(x%10!=4&&x%10!=7) return 0;
        x/=10;
    }
    return 1;
}
unordered_map<int,int> mp[100000+10][2][2];

int dfs(int x,int y,int cx,int cy,int cur) {
    //printf("%d %d %d %d %d\n", x,y,cx,cy,cur);
    if (cur == n+1) {
        bool ok=0;
        if (cx == 1 && y == 0) ok=1;
        if (cy == 1 && x == 0) ok=1;
        if (cx == 1 && cy == 1) ok = 1;
        if (ok) {
            printf("Yes\n");
            exit(0);
        }
        return ok;
    }
    if (mp[x][cx][cy].count(y))
        return mp[x][cx][cy][y];

    int ret = 0;
    if (s[cur] & 1) {
        if (x == 0) {
            ret = max(ret, dfs(cur,y,0,cy,cur+1));
        } else {
            if (cur-x<=k)
                ret = max(ret, dfs(cur,y,1,cy,cur+1));
            else {
                if (cx == 1)
                    ret = max(ret, dfs(cur,y,0,cy,cur+1));
            }
        }
    }
    if (s[cur] & 2) {
        if (y == 0) {
            ret = max(ret, dfs(x,cur,cx,0,cur+1));
        } else {
            if (cur-y<=k)
                ret = max(ret, dfs(x,cur,cx,1,cur+1));
            else {
                if (cy == 1)
                    ret = max(ret, dfs(x,cur,cx,0,cur+1));     
            }
        }
    }
    return mp[x][cx][cy][y] = ret;
}
int main() {
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        if (chk1(a[i])) s[i]|=1;
        if (chk2(a[i])) s[i]|=2;
        if (s[i]==0) return !printf("No\n");
    }
    printf("%s\n", dfs(0,0,0,0,1)?"Yes":"No");
}

但是,我们应该相信珂学的!

我们不妨这么来设计状态:用dp[now][x][y][cx][cy]表示,now位置之前考虑好了,现在在施展now位置。

1)x: now与上一个A班孩子的距离

2)y: now与上一个B班孩子的距离。

注: 当距离大于20时,是没有区别的,所以把大于20的距离都看成21就好了

3)cx: 上一个A班的孩子有没有朋友

4)cy: 上一个B班的孩子有没有朋友。

#include <iostream>
#include <vector>
#include <unordered_map>
#include <bitset>
using namespace std;
const int N=100000+10;
bitset<N> vis[22][22][3][3],dp[22][22][3][3];

int n,k,a[N],s[N];

bool chk1(int x) {
    vector<int> v;
    while(x) v.push_back(x%10), x/=10;
    for(int i=0;i<v.size();i++) 
        if (v[i] != v[v.size()-1-i])
            return 0;
    return 1;
}                                                               
                                                            
bool chk2(int x) {
    while(x) {                                                          
        if(x%10!=4&&x%10!=7) return 0;                      
        x/=10;                                                      
    }
    return 1;
}

int dfs(int now,int dx,int dy,int cx,int cy) {
    //printf("%d %d %d %d %d\n",now,dx,dy,cx,cy);
    if (now == n+1) {
        if (cx==0||cy==0) return 0;
        return 1;
    }
    if(vis[dx][dy][cx][cy][now]) {
        return dp[dx][dy][cx][cy][now];
    }
    bool ret = 0; vis[dx][dy][cx][cy][now] = 1;
    if (s[now]&1) {
        if (dx==k+1&&cx==0){}
        else ret|=dfs(now+1,1,min(dy+1,k+1),dx<=k?1:0,cy);
    }
    if (s[now]&2) {
        if (dy==k+1&&cy==0) {}
        else ret|=dfs(now+1,min(dx+1,k+1),1,cx,dy<=k?1:0);
    }


    return dp[dx][dy][cx][cy][now]=ret;
}

int main() {
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        if (chk1(a[i])) s[i]|=1;
        if (chk2(a[i])) s[i]|=2;
        if (s[i]==0) return !printf("No\n");
    }
    printf("%s\n", dfs(1,k+1,k+1,1,1)?"Yes":"No");
}
posted @ 2018-05-08 17:20  RUSH_D_CAT  阅读(354)  评论(0编辑  收藏  举报