2021牛客暑期多校训练营8 F. Robots

F. Robots

题意:

给定n * m的矩阵,其中有一些格子无法经过,存在三种类型的移动方式。
1.(x, y) —>(x + 1, y )
2.(x,y) —>(x, y + 1)
3.(x, y) —>(x + 1, y) || (x, y + 1)
给定q个查询,每次查询询问某种移动方式是否能从(x1, y1) --> (x2, y2)
n , m < = 500 , q < = 5 e 5 n , m <= 500, q <= 5e5 n,m<=500,q<=5e5

思路:

考虑到q次查询,如若对每次进行暴力dp求解,时间复杂度为O(q * n * m) >> O(n * m * n * m)
预处理离线肯定是优于每次在线查询。
考虑暴力f[i][j][k][t]:从起点(i,j)是否能到达(k,t)。时间复杂度O(n * m * n * m)也会TLE。
如果之前写过 可达性统计, 就会很容易想到存储一个用bitset存储一个可达图。
假设当前点(i,j)可经过,那么所有能到达(i,j-1) 和 (i - 1, j)的点的起点也可以到达该点。相当于是维护以当前点为终点,其左上有多少点可到达该点的一个图。
mm[i][j] == 1表示不可经过。
bitset<N * N> f[i][j]
i f ( m m [ i ] [ j ] = = 0 )    f [ i ] [ j ] [ ( i − 1 ) ∗ m + j ) = 1 , f [ i ] [ j ] = f [ i − 1 ] [ j ]    o r    f [ i ] [ j − 1 ] if(mm[i][j] == 0) \;f[i][j][(i - 1) * m + j) = 1, f[i][j] = f[i - 1][j] \;or \;f[i][j - 1] if(mm[i][j]==0)f[i][j][(i1)m+j)=1,f[i][j]=f[i1][j]orf[i][j1]
e l s e    f [ i ] [ j ] . r e s e t ( ) else \;f[i][j].reset() elsef[i][j].reset() //说明当前点的左上区域无点可到达当前点。

code:

int mm[maxn][maxn];
struct note{
	int id;
	int ty;
	int x;
	int y;	
};
vector <note> alls[maxn][maxn];
bitset <maxn * maxn> f[maxn];
bool ans[N];
int main()
{	
	int n, m;
	scanf("%d %d", &n, &m);
	for(int i = 1 ; i <= n ; i ++)
	{
		for(int j = 1 ; j <= m ; j ++)
		scanf("%1d", &mm[i][j]);
	}
	int q;
	scanf("%d", &q);
	for(int i = 1 ; i <= q ; i ++)
	{
		int t, x1, y1, x2, y2;
		scanf("%d %d %d %d %d", &t, &x1, &y1, &x2, &y2);
		alls[x2][y2].push_back({i, t, x1, y1});
	}
	for(int i = 1 ; i <= n ; i ++)
	{
		for(int j = 1 ; j <= m ; j ++)
		{
			if(mm[i][j] == 0)
			{
				f[j][(i - 1) * m + j] = 1;
				f[j] |= f[j - 1]; //当前层 
                f[j] |= f[j];  // 上一层 
			}
			else
			f[j].reset();
			for(auto t : alls[i][j])
			{
				if(t.ty == 1)
				{
					if(t.y == j) //同列 
					ans[t.id] = f[j][(t.x - 1) * m + t.y];
				}
				else if(t.ty == 2)
				{
					if(t.x == i) //同行 
					ans[t.id] = f[j][(t.x - 1) * m + t.y];
				}
				else
				{
					ans[t.id] = f[j][(t.x - 1) * m + t.y];
				}
			}
		}
	}
	for(int i = 1 ; i <= q ; i ++)
	{
		if(ans[i]) printf("yes\n");
		else printf("no\n");
	}
	return 0;
}	
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值