2021牛客暑期多校训练营8-F题

F题:Robots

原题

题目大意

请添加图片描述

solution

先讨论几种情况

  • 机器人是只能向下移动的(1)
  • 机器人是只能向右移动的(2)
  • 机器人是能向右或向下移动的(3)

对于(1)(2)情况,可以求一遍前缀和,当起点和终点之间全是0时即可以走到。
对于(3)情况,考虑使用dp,但需要枚举所有起点终点,时间复杂度 O ( n 4 ) O(n^4) O(n4),显然不行。然而观察数据可以发现 O ( n 4 w ) O(\frac{n^4}{w}) O(wn4)的复杂度恰好可以过题,于是想到使用bitset将复杂度降低。
由于询问次数 q q q较大,可以将所有的询问先读进来,然后离线处理。
具体而言
将当前行上每个起点出发的询问,存储到终点的每行中 。
也就是将前两个维度删去,算出同一终点(或起点)的情况。
因为只存在0、1,可以用bitset的位运算优化。

code

#include<bits/stdc++.h>
using namespace std;
const int N=510;
int n,m,q,op,lx,ly,rx,ry;
struct node {
	int id,rx,ly,ry;
};
vector <node> v[N],t[N];
char c[N][N];
int dx[N][N],dy[N][N],ans[500010];
bitset <N> b[N];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%s",c[i]+1);
		for(int j=1;j<=m;j++){
			dx[i][j]=dx[i][j-1]+(c[i][j]=='1');//前缀和
			dy[i][j]=dy[i-1][j]+(c[i][j]=='1');
		}
	}
	scanf("%d",&q);
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d%d%d%d",&op,&lx,&ly,&rx,&ry);
		if(op==1){//通过前缀和判断只能向下走
			if(ly==ry&&rx-lx>=0&&dy[rx][ry]-dy[lx-1][ly]==0)
			ans[i]=1;
		}
		else if(op==2){//通过前缀和判断只能向右走
			if(lx==rx&&ry-ly>=0&&dx[rx][ry]-dx[lx][ly-1]==0)
			ans[i]=1;
		}
		else if(lx<=rx&&ly<=ry)//储存离线处理
			v[lx].push_back(node{i,rx,ly,ry});
	}
	for(int l=1;l<=n;l++)
	{
		//将当前行上每个起点出发的询问,存储到终点的每行中 。
		for(int i=0;i<v[l].size();i++)
		t[v[l][i].rx].push_back(v[l][i]);
		for(int i=1;i<=m;i++) b[i].reset();
		//b[y][x]表示是否能从(l,x)走到了(l,y)
		for(int i=1;i<=m;i++)
		{
			//若(l,i)有障碍物,清零 
			if(c[l][i]=='1') b[i].reset();
			//(l,i)无障碍物,标记(l,i) 可以走到 (l,i) ,合并上能走到 (l,i-1) 的起点方案 
			else {
				b[i][i]=1;
				b[i]|=b[i-1];
			}
		}
		for(int r=l;r<=n;r++)
		{
			for(int i=1;i<=m;i++)
			{
				//走到 (r,i) 的方案,要合并上能走到 (r,i-1) 的方案 
				b[i]|=b[i-1];
				//若 (r,i) 存在障碍物,则无方案 
				if(c[r][i]=='1') b[i].reset();
			}
			for(int i=0;i<t[r].size();i++)
				ans[t[r][i].id]=b[t[r][i].ry][t[r][i].ly];
			t[r].clear();
		}
	}
	for(int i=1;i<=q;i++)
	{
		if(ans[i])printf("yes\n") ;
		else printf("no\n");
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值