codeforces1236D 2100分模拟

本文探讨了一种在二维迷宫中遍历所有非障碍格子的算法,通过使用螺旋形路径和二分查找障碍位置的方法,确保了每个格子仅被访问一次,并在变换方向时遵循特定规则。

题目传送门

题意:

\dpi{150}n*m 的迷宫,有 k 个格子是障碍,移动的方向是上下左右。

每个格子只能经过一次。

每个格子在经过时若要变换方向,只能向右变换一次。

问从 (1,1) 出发,能否遍历所有非障碍的格子。

数据范围:1 \leqslant n,m \leqslant 10^5 ,0 \leqslant k \leqslant 10^5 。

题解:

走的轨迹大致是一个螺旋形。

在可以直走和拐弯时,选择直走,因为拐弯后不可能走到原来直走的格子上。

用set存储障碍。然后二分障碍的位置就好了。

如果可以完成任务,那么走的路径长度是 n*m-k-1 。

感受:

在AC之前能不看数据就不看数据。

代码:

#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 1e5 + 5 ;
int n , m , k ;
set<int> row[maxn] , col[maxn] ;
ll s = 0 ;
int r , c , d ;
int ur , dr , lc , rc ;
bool can()
{
	if(d == 0)  
	{
	   auto it = row[r].upper_bound(c) ;
	   int nxt ;
	   if(it == row[r].end())  nxt = m ;
	   else  nxt = *it - 1 ;
	   nxt = min(nxt , rc - 1) ;
	   if(nxt <= c)  return 0 ;
	   else  return 1 ;	
	}
	else if(d == 1)
	{
	   auto it = col[c].upper_bound(r) ;
	   int nxt ;
	   if(it == col[c].end())  nxt = n ;
	   else  nxt = *it - 1 ;
	   nxt = min(nxt , dr - 1) ;
	   if(nxt <= r)  return 0 ;
	   else  return 1 ;	
	}
	else if(d == 2)
	{
	   auto it = row[r].upper_bound(c) ;
	   if(it != row[r].begin())  it -- ;
	   int nxt ;
	   if(it == row[r].end() || (*it) > c)  nxt = 1 ;
	   else  nxt = (*it) + 1 ;
	   nxt = max(nxt , lc + 1) ;
	   if(nxt >= c)  return 0 ;
	   else  return 1 ;	
	}
	else
	{
	   auto it = col[c].upper_bound(r) ;
	   if(it != col[c].begin())  it -- ;
	   int nxt ;
	   if(it == col[c].end() || (*it) > r)  nxt = 1 ;
	   else  nxt = (*it) + 1 ;
	   nxt = max(nxt , ur + 1) ;
	   if(nxt >= r)  return 0 ;
	   else  return 1 ;		
	}
}
void work()
{
	if(d == 0)  
	{
	   auto it = row[r].upper_bound(c) ;
	   int nxt ;
	   if(it == row[r].end())  nxt = m ;
	   else  nxt = *it - 1 ;
	   nxt = min(nxt , rc - 1) ;
	   s += nxt - c ;
	   c = nxt ;
	   rc = min(rc , c) ;
	}
	else if(d == 1)
	{
	   auto it = col[c].upper_bound(r) ;
	   int nxt ;
	   if(it == col[c].end())  nxt = n ;
	   else  nxt = *it - 1 ;
	   nxt = min(nxt , dr - 1) ;
	   s += nxt - r ;
	   r = nxt ;
	   dr = min(dr , r) ;
	}
	else if(d == 2)
	{
	   auto it = row[r].upper_bound(c) ;
	   if(it != row[r].begin())  it -- ;
	   int nxt ;
	   if(it == row[r].end() || (*it) > c)  nxt = 1 ;
	   else  nxt = (*it) + 1 ;
	   nxt = max(nxt , lc + 1) ;
	   s += c - nxt ;
	   c = nxt ;
	   lc = max(lc , c) ;
	}
	else
	{
	   auto it = col[c].upper_bound(r) ;
	   if(it != col[c].begin())  it -- ;
	   int nxt ;
	   if(it == col[c].end() || (*it) > r)  nxt = 1 ;
	   else  nxt = (*it) + 1 ;
	   nxt = max(nxt , ur + 1) ;
	   s += r - nxt ;
	   r = nxt ;
	   ur = max(ur , r) ;		
	}
}
void solve()
{ 
   r = 1 , c = 1 , d = 0 ;
   ur = 1 , dr = n + 1 , lc = 0 , rc = m + 1 ;
   while(1)
   {
      if(can())  
	    work() ;
      else 
	  {
	  	 d = (d + 1) % 4 ;
	  	 if(can())  
		   work() ;
         else  break ;
	  }	  
   }	
}
int main()
{
	scanf("%d%d%d" , &n , &m , &k) ;
	for(int i = 1 ; i <= k ; i ++)
    {
    	int r , c ;
    	scanf("%d%d" , &r , &c) ;
    	row[r].insert(c) ;
    	col[c].insert(r) ;
	}
	solve() ;
	if(s == ll(n) * m - k - 1)  printf("Yes\n") ;
	else  printf("No\n") ;
	return 0 ;
}

 

「LLM那些事」系列第 4 篇《上下文窗口的边界》,文章连接:https://blog.csdn.net/houwenjin/article/details/163999753。 演示什么:在「预测」Sheet 的黄色格子里输入一句话(默认「来泡一杯」),四个「模型」——别只统计最后 1 / 2 / 3 / 4 个字的 n-gram 查表——同时预测下一个字。同一个输入,看的上下文越长,候选越少、预测越确定: ┌────────────────┬──────────┬───────────────┬──────┐ │ 只看最后几个字 │ 用的前缀 │ 候选下一字数 │ 预测 │ ├────────────────┼──────────┼───────────────┼──────┤ │ 1 个 │ 杯 │ 3(茶/子/水) │ 模糊 │ ├────────────────┼──────────┼───────────────┼──────┤ │ 2 个 │ 一杯 │ 2(茶/水) │ 收窄 │ ├────────────────┼──────────┼───────────────┼──────┤ │ 3 个 │ 泡一杯 │ 1(茶) │ 确定 │ ├────────────────┼──────────┼───────────────┼──────┤ │ 4 个 │ 来泡一杯 │ 1(茶) │ 确定 │ └────────────────┴──────────┴───────────────┴──────┘
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值