牛客第八场 F题 Robots 离线分治+bitset优化dp

题意:给一张n*m的图,上面有若干障碍物,现在有3种机器人,1只能往下走,2只能往右走,3可以往下往右走,对于q次询问,回答对应机器人是否能到达目的地。

思路:赛场上想到了要分治,但是具体处理有问题,也没想到用bitset优化DP,所以没过。

题解:对于q次询问,1和2类型的机器人我们可以预先处理掉,然后对于类型三的机器人,我们对其中一维进行分治。

区域分成两半,然后开一个DP数组,存储从x,y开始到达Mid分界线的可达性。显然正常开数组需要三维。

dp[x][y][z]表示x,y开始能否到达mid,z,但是这里可以利用bitset优化。

然后我们就能获得起点到分界线与终点到分界线的可达情况,进行一次与操作,如果互相可达,那么与之后的数一定不等于0。

 

对于在分界线两边的询问,我们这样就处理完了,对于分界线一边的点,我们继续分治就行。

时间复杂度qlogn+n^3logn/32

 

下附代码:

#include<bits/stdc++.h>
using namespace std;
bool g[505][505];
int ed1[505][505],ed2[505][505];
char s[505];
int res[500005];
int n,m,q;
struct node{
    int x1,y1,x2,y2,pos;
};
vector<node> v;
bitset<505> dp[505][505];
void solve(int l,int r,vector<node> &v){
    if (l==r){
        for (auto x:v){
            int st=x.y1,ed=x.y2;
            if (ed1[l][ed]-ed1[l][st-1]==0) res[x.pos]=1;
            else res[x.pos]=0;
        }
        v.clear();
        return;
    }
    int mid=(l+r)>>1;
    for (int i=m; i>=1; i--){
        dp[mid][i].reset();
        if (!g[mid][i]){
            dp[mid][i].set(i);
            dp[mid][i]|=dp[mid][i+1];
        }
    }
    for (int i=1; i<=m; i++){
        dp[mid+1][i].reset();
        if (!g[mid+1][i]){
            dp[mid+1][i].set(i);
            dp[mid+1][i]|=dp[mid+1][i-1];
        }
    }
    for (int i=m; i>=1; i--){
        for (int j=mid-1; j>=l; j--){
            if (g[j][i]){
                dp[j][i].reset();
                continue;
            }
            dp[j][i]=dp[j][i+1]|dp[j+1][i];
        }
    }
    for (int i=1; i<=m; i++){
        for (int j=mid+2; j<=r; j++){
            if (g[j][i]){
                dp[j][i].reset();
                continue;
            }
            dp[j][i]=dp[j][i-1]|dp[j-1][i];
        }
    }
    vector<node> vl,vr;
    for (auto x:v){
        if(x.x1<=mid && x.x2>mid){
            if ((dp[x.x1][x.y1]&dp[x.x2][x.y2]).count()) res[x.pos]=1;
        }
        else if(x.x2<=mid) vl.push_back(x);
        else vr.push_back(x);
    }
    v.clear();
    solve(l,mid,vl);
    solve(mid+1,r,vr);
}
int main(){
    scanf("%d%d",&n,&m);
    for (int i=1; i<=n; i++){
        scanf("%s",s);
        for (int j=0; j<m; j++){
            g[i][j+1]=s[j]-'0';
            ed1[i][j+1]=ed1[i][j]+g[i][j+1];
            ed2[i][j+1]=ed2[i-1][j+1]+g[i][j+1];
        }
    }
    scanf("%d",&q);
    int p=0;
    int tt=q;
    while (q--){
        int z,a,b,c,d;
        scanf("%d%d%d%d%d",&z,&a,&b,&c,&d);
        if (z==1){
            if (b!=d || a>c){
                res[++p]=0;
            }
            else {
                if (ed2[c][b]-ed2[a-1][b]==0){
                    res[++p]=1;
                }
                else res[++p]=0;
            }
        }
        else if (z==2){
            if (a!=c || b>d){
                res[++p]=0;
            }
            else {
                if (ed1[a][d]-ed1[a][b-1]==0){
                    res[++p]=1;
                }
                else res[++p]=0;
            }
        }
        else {
            if (a>c || b>d){
                res[++p]=0;
            }
            else {
                v.push_back({a,b,c,d,++p});
            }
        }
    }
    solve(1,n,v);
    for (int i=1; i<=tt; i++){
        if (res[i]) printf("yes\n");
        else printf("no\n");
    }
}
View Code

 

posted @ 2021-08-13 14:12  我是菜狗QAQ  阅读(27)  评论(0编辑  收藏  举报