题解:CF1611G Robot and Candies

posted on 2024-07-15 02:11:29 | under | source

观察、转化,然后贪心。

显然,假如将原网格黑白染色,那么不同颜色互不影响。

考虑相同颜色,那么机器人实际上是在对角线上移动。对于一条从左上到右下的对角线,可以发现线上的点 \(x+y\) 是固定的。同理,对于另一类对角线,\(x-y\) 是固定的。

所以可以用数值描述一条对角线。记 \(a,b\) 分别表示为经过该点的两条对角线,有 \(a=x+y,b=x-y\)

容易发现,一个点可以到达的点构成一个以它为顶点的正三角。进一步观察得知,\((a,b)\) 可以到达 \((p,q)\),当且仅当 \(a\le p\)\(b\le q\)

所以原问题转化为序列问题。首先对第一维排序,考虑第二维。那么就是求至少几个上升子序列可以将原序列覆盖。

直接贪心即可,具体的,维护当前上升子序列的末尾元素集合 \(S\),假如新增一个元素 \(x\),我们肯定要让 \(S\) 的下界尽量小,也就是选取最大的 \(p\in S\),满足 \(p\le x\)

#include<bits/stdc++.h>
using namespace std;

const int N = 1e6 + 5;
int T, n, m, na, nb, ans;
char c[N];
struct node{int x, y;} A[N], B[N];

inline bool cmp(node A, node B) {return A.x == B.x ? A.y < B.y : A.x < B.x;}
inline void solve(node A[], int n){
	set<int> s;
	sort(A + 1, A + 1 + n, cmp);
	for(int i = 1; i <= n; ++i){
		if(s.empty()) s.insert(A[i].y), ++ans;
		else{
			if(*s.begin() > A[i].y) s.insert(A[i].y), ++ans;
			else{
				auto lsy = s.upper_bound(A[i].y); --lsy;
				s.erase(*lsy), s.insert(A[i].y);
			}
		}
	}
}
signed main(){
	cin >> T;
	while(T--){
		scanf("%d%d", &n, &m), ans = na = nb = 0;
		for(int i = 1; i <= n; ++i){
			scanf("%s", c + 1);
			for(int j = 1; j <= m; ++j){
				if(c[j] == '1') 
					if((i + j) & 1) A[++na] = {i + j, i - j};
					else B[++nb] = {i + j, i - j};
			}
		}
		solve(A, na), solve(B, nb);	
		printf("%d\n", ans);
	}
	return 0;
}
posted @ 2026-01-15 08:16  Zwi  阅读(3)  评论(0)    收藏  举报