Codeforces 1428D Bouncing Boomerangs

Codeforces 1428D Bouncing Boomerangs

Translate

题目链接

在一个 n×n 的网格图中,在下面的每一列都会射出一个飞镖,在 n×n 的网格图中会有若干个目标,如果飞镖遇到目标则顺时针旋转 90 后继续飞行直到飞出网格图。

规定在每一行每一列最多有 2 个目标,第 i 行的飞镖会旋转 ai 次,现给定 ai, 构造出一组合法的解(确定网格图中的目标的个数和位置)。

n105,0ai3

凉心构造题。

Solution

对于 ai=0,忽略这个地方,不会对答案产生什么影响。

先处理 ai=1 的情况,因为 ai=2,3 会依靠另一列来进行第二、三次反弹,而 ai=1 不需要考虑,直接出去占用一行就可以。怎样占用最优?因为其它 3 匹配这个 1 进行三次反弹的时候需要上面多开一行,所以从下往上依次占用。

从左往右找 ai=2,之后再找到右边第一个没有被前面的 2 匹配的 1,匹配到一起,也就是利用这个 1 的这一列目标进行第二次反弹。

为什么找右边第一个 1 ? 因为 2 需要右边的 1 来反弹,贪心一下是选尽量靠左的更优,把尽量靠右让给右边的 2

为什么先找 ai=2?因为 ai=3 可以依靠其他的 1,2,3 进行 3 次反转。

最后就是 ai=3 的情况,它可以有三种方法来进行三次反弹:

  1. 右边没有被其它 2,3 匹配的 1

  2. 右边没有被其它 3 匹配的 2

  3. 右边没有被其它 3 匹配的 3

因为可以从右边的 3 来反弹,所以这里 3 从后往前匹配找。

ai=2,3 去匹配的时候采用双指针扫,一个扫 ai=2,3,一个扫哪一位可以匹配。如果没扫到就是无解。

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
#define re register
//#define int long long
inline int Max(int x, int y) { return x > y ? x : y; }
inline int Min(int x, int y) { return x < y ? x : y; }
inline int Abs(int x) { return x < 0 ? ~x + 1 : x; }
inline int read() {
	int r = 0;
	bool w = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9') {
		if(ch == '-') w = 1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9') {
		r = (r << 3) + (r << 1) + (ch ^ 48);
		ch = getchar();
	}
	return w ? ~r + 1 : r;
}
//#undef int
const int N = 300010;
bool f;
int n, a[N], cnt, ansx[N], ansy[N];
bool vis[N];
int row[N], rowcnt; 
signed main() {
	n = read();
	for(int i = 1; i <= n; ++i) a[i] = read();
	//先把所有的1一行一行开 
	for(int i = 1; i <= n; ++i)
		if(a[i] == 1) ++cnt, ansx[cnt] = i, ansy[cnt] = ++rowcnt, row[i] = rowcnt;
	int pos = 1;
	//2和右边第一个1匹配 
	for(int i = 1; i <= n; ++i) {
		if(a[i] == 2) {
			pos = Max(pos, i);
			while(a[pos] != 1 && pos <= n) ++pos;
			if(pos == n + 1) {
				puts("-1");
				return 0;
			}
			++cnt;
			ansx[cnt] = i, row[i] = ansy[cnt] = row[pos];
			vis[pos] = 1;
			++pos;
		}
	}
	//3和右边三种情况匹配 
	pos = n;
	for(int i = n; i >= 1; --i) {
		if(a[i] == 3) {
			while(!((a[pos] == 1 && !vis[pos]) || a[pos] == 2 || (a[pos] == 3 && row[pos])) && pos >= i) --pos;
			if(pos == i - 1) {
				puts("-1");
				return 0;
			}
			++cnt; ansx[cnt] = i, ansy[cnt] = ++rowcnt;
			++cnt; ansx[cnt] = pos, ansy[cnt] = rowcnt;
			row[i] = rowcnt;
			--pos;
		}
	}
	//无解 
	if(cnt > n << 1 || rowcnt > n) {
		puts("-1");
		return 0;
	}
	printf("%d\n", cnt);
	for(int i = 1; i <= cnt; ++i) printf("%d %d\n", n - ansy[i] + 1, ansx[i]);
	return 0;
}
posted @   do_while_true  阅读(179)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· .NET Core 中如何实现缓存的预热?
· 三行代码完成国际化适配,妙~啊~
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?

This blog has running: 1845 days 2 hours 1 minutes 59 seconds

点击右上角即可分享
微信分享提示