CF1428D Bouncing Boomerangs 题解
解题思路
很简单的贪心。
观察发现以下性质:
- 当
时,这一行一定只有两个目标,且第二个目标一定位于一个 的格子内; - 当
,那么当前列右边某一列发生转向的地方, ;
那么这道题就基本已经做出来了。因为
注意,我们填的时候不需要考虑有没有填过,直接无脑填就可以了,最后再去重。
综上,本题步骤如下:
- 从左往右找到所有
的列,并按顺序放入一个队列中; - 从左往右枚举
的列,并不断弹出队首直到队首列在当前列右侧,然后在队首列填入一个目标,并标记为已填; - 清空队列,从左往右枚举所有非
列,并放入队列中; - 从左往右枚举
的列,找到第一个在当前列右侧的列,然后填入两个目标; - 枚举剩余的没有被填过的
的列,向其中填入一个目标; - 排序去重输出答案。
注意事项
- 在维护可填列的时候一定要使用队列来维护,贪心地从左往右填;
- 注意纵坐标是从上往下递增的,而不是从下往上。
AC 代码
应该是比较短的代码了吧……
#include<bits/stdc++.h>
#define N 100005
#define p push_back
#define C continue
#define re register
#define pii std::pair<int,int>
std::vector<pii> A;
int n,a[N],vis[N];
signed main(){scanf("%d",&n);
for(re int i=1;i<=n;++i)
scanf("%d",&a[i]);
std::queue<int> q;
for(re int i=1;i<=n;++i)
if(a[i]==1) q.push(i);
for(re int i=1;i<=n;++i){
if(a[i]!=2) C;
while(q.size()&&q.front()<i) q.pop();
if(q.empty()){puts("-1");return 0;}
A.p({i,i});
A.p({i,q.front()});
vis[q.front()]=1;q.pop();
}while(q.size()) q.pop();
for(re int i=1;i<=n;++i){
if(a[i]!=0&&!vis[i]) q.push(i);
}for(re int i=1;i<=n;++i){
if(a[i]!=3) C;
while(q.size()&&q.front()<=i) q.pop();
if(q.empty()){puts("-1");return 0;}
A.p({i,i});A.p({i,q.front()});
A.p({q.front(),q.front()});
vis[q.front()]=1;q.pop();
}for(re int i=1;i<=n;++i){
if(a[i]!=1) C;
if(vis[i]) C;A.p({i,i});
}std::sort(A.begin(),A.end());
int res=std::unique(A.begin(),A.end())-A.begin();
printf("%d\n",res);
for(re int i=0;i<res;++i){
printf("%d ",A[i].first);
printf("%d\n",A[i].second);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下