题解: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;
}

浙公网安备 33010602011771号