CF1948C Arrow Path

CF1948C Arrow Path

做法一:记忆化搜索

注意到向左箭头没有用,当前点能到的充要条件是左边相邻点是右箭头,于是考虑左边相邻点可以从哪些点转移得到,由此记忆化搜索,时间复杂度 \(O(n)\)。

解释一下 \((2, n)\) 为什么不能由上方的 \((1,n)\) 走一步得到:但凡草稿上模拟一下过程就知道 \((1, n)\) 不能作为一次完整操作的终点,所以这个做法是对的。

#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l); i <= (r); ++ i)
#define G(i,r,l) for(int i(r); i >= (l); -- i)
using namespace std;
using ll = long long;
const int N = 3e5;
int f[3][N], vis[3][N]; 
int n; 
string s[3]; 
int solve(int x, int y){
//	printf("(%d %d) ->\t", x, y);
	if(y < 1) return 0;
	if(vis[x][y] == 1) return f[x][y];
	if(x == 1){
		if(y > 1 && s[x][y - 1] == '>'){
			f[x][y] = solve(x + 1, y - 1) | solve(x, y - 2);
		}
	}
	else{
		if(y > 1 && s[x][y - 1] == '>'){
			f[x][y] = solve(x - 1, y - 1) | solve(x, y - 2);
		}
	}
	vis[x][y] = 1;
	return f[x][y];
}
void Main(){
	cin >> n;
	cin >> s[1] >> s[2];
	s[1] = " " + s[1];
	s[2] = " " + s[2];
	F(i, 1, 2){
		F(j, 1, n){
			f[i][j] = 0;
			vis[i][j] = 0;
		} 
	}
	f[1][1] = 1;
	vis[1][1] = 1;
	solve(2, n); 
	if(f[2][n] == 1){
		cout << "YES\n";
	}
	else{
		cout << "NO\n";
	}
	return ;
}
signed main(){
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int T;
	cin >> T;
	while(T --) Main();
	return fflush(0), 0;
}

做法二:考虑转移本质

用 / 表示能作为中转点的点,发现是这样分布的:(#表示起点或终点)

# / # / # / #
/ # / # / # /

很好理解,因为每次移动的曼哈顿距离是偶数。

所以问题转化成是否存在一处位置不能前进。等价于是否有两个相邻的 < 。注意有两种情况:

# / # < #    # < # / #
/ # < # /    / # < # / 

直接for就可以了。时间复杂度同样 \(O(n)\),空间复杂度更小。

#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l); i <= (r); ++ i)
#define G(i,r,l) for(int i(r); i >= (l); -- i)
using namespace std;
using ll = long long;
const int N = 3e5;
int n; 
string s[3];
int f[3][N]; 
void Main(){
	cin >> n;
	cin >> s[1] >> s[2];
	s[1] = " " + s[1];
	s[2] = " " + s[2]; 
	int flag = 1; 
	for(int i = 2; i <= n; i += 2){
		if(s[1][i] == '<' && s[2][i - 1] == '<'){
			flag = 0;
			break;
		}
		if(s[1][i] == '<' && s[2][i + 1] == '<'){
			flag = 0;
			break;
		}
	}
	if(flag == 0){
		cout << "NO\n";
	}
	else{
		cout << "YES\n";
	}
	return ;
}
signed main(){
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int T;
	cin >> T;
	while(T --) Main();
	return fflush(0), 0;
}

一个语法上的警示,这样写是错的:

cin >> s[1] >> s[2];
F(i, 1, 2){
	G(j, n, 1){
		s[i][j] = s[i][j - 1];
	}		
}

C++20及以后删除了 cin >> (s + 1) 的写法。

posted @ 2026-09-25 22:10  superl61  阅读(3)  评论(0)    收藏  举报