随笔 - 216,  文章 - 0,  评论 - 17,  阅读 - 25446

比赛链接:

https://codeforces.com/contest/1623

A. Robot Cleaner

题目大意:

nm 的地图中,清洁机器人在(rbcb)的位置,每一秒,机器人移动 dx 行、dy 列并清洁所在行和列所有的单元格,刚开始的时候,dx = 1,dy = 1,当机器人碰到边界时,朝反方向移动,即当机器人碰到上下边界时,dx=dx,碰到左右边界的时候,dy=dy。脏的单元格在(rdcd),求第几秒的时候脏的单元格被清洁。

思路:

直接通过模拟,暴力求解。

#include <bits/stdc++.h>
using namespace std;
#define LL long long
LL T = 1;
void solve(){
	int n, m, a, b, c, d, ans = 0, dx = 1, dy = 1;
	cin >> n >> m >> a >> b >> c >> d;
	while (a != c && b != d){
		if (a == n && dx == 1) dx = -1;
		else if (a == 1 && dx == -1) dx = 1;
		if (b == m && dy == 1) dy = -1;
		else if (b == 1 && dy == -1) dy = 1;
		a += dx;
		b += dy;
		ans++;
	}
	cout << ans << "\n";
}
int main(){
	cin >> T;
	while(T--)
		solve();
	return 0;
}

显然,当机器人所在的行或列在要被清洗的行或列的左上方,那么清洗单元格需要花费的时间是二者之差,否则的话,机器人需要改变方向后才能清洗,所以所花的时间就是机器人到边界后再去清洗的时间。
所以我们可以有 O(1) 的解法。

#include <bits/stdc++.h>
using namespace std;
#define LL long long
LL T = 1;
void solve(){
	int n, m, a, b, c, d;
	cin >> n >> m >> a >> b >> c >> d;
	cout << min(c >= a ? c - a : 2 * n - a - c, d >= b ? d - b : 2 * m - d - b) << "\n";
}
int main(){
	cin >> T;
	while(T--)
		solve();
	return 0;
}

B. Game on Ranges

题目大意:

Alice 有一个包含不相交的整数范围的集合,初始的范围是从 1 到 n,每一个回合 Alice 都会选择集合中的一个范围,然后 Bob 选择这个范围的一个数字,删除这个数,同时分隔这个范围集合。现已知 Alice 每一回合选取的整数范围,让你求对应的回合中 Bob 选择的是哪个数。

思路:

数据的范围为 [l,r]
l==r 的时候,只有一个数可以选。
而左右边界不相等的时候,选择一个数之后,下一回合的范围一定有一个边界与当前的一个边界是一样的,所以,我们可以遍历所有的区间,去寻找有匹配的,然后输出选择的那个数即可。

代码:

全部查找了一遍

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e3 + 10;
LL T = 1, n, l[N], r[N];
void solve(){
	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> l[i] >> r[i];
	for (int i = 0; i < n; i++){
		LL ans = l[i];
		for (int j = 0; j < n; j++)
			if (l[i] == l[j] && r[i] > r[j]) ans = max(ans, r[j] + 1);  //若没有与左边界匹配的范围的话,肯定是删除了左边界这个点。
		printf("%lld %lld %lld\n", l[i], r[i], ans);
	}
}
int main(){
	cin >> T;
	while(T--)
		solve();
	return 0;
}

先排序(减少了查找的次数),然后再查找

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e3 + 10;
LL T = 1, n;
struct node {
	int l, r;
}nd[N];
bool cmp(node a, node b){
	if (a.r - a.l == b.r - b.l) return a.l < b.l;
	return a.r - a.l > b.r - b.l;
}
void solve(){
	scanf("%lld", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d %d", &nd[i].l, &nd[i].r);
	sort(nd + 1, nd + n + 1, cmp);
	for (int i = 1; i <= n; i++){
		if (nd[i].l == nd[i].r){
			printf("%d %d %d\n", nd[i].l, nd[i].r, nd[i].l);
			continue;
		}
		for (int j = i + 1; j <= n; j++){
			if (nd[i].l == nd[j].l){
				printf("%d %d %d\n", nd[i].l, nd[i].r, nd[j].r + 1);
				break;
			}
			else if (nd[i].r == nd[j].r){
				printf("%d %d %d\n", nd[i].l, nd[i].r, nd[j].l - 1);
				break;
			}
		}
	}
	cout << "\n";
}
int main(){
	cin >> T;
	while(T--)
		solve();
	return 0;
}

C. Balanced Stone Heaps

题目大意:

n 堆石头,你可以按照从第 3 个到第 n 个石堆这个顺序,选择第 i 个石堆,然后拿走 3 * d 个石子,给第 i - 1 个石堆 d 个石子,给第 i - 2 个石堆 d * 2 个石子,求最小的石堆最大的石子数会是多少?

思路:

将石堆的顺序过来,就是从第 1 个石堆拿出 3 * d 个石子,然后分给第 i + 1 个石堆 d 个石子,第 i + 2 个石堆 d * 2 个石子,然后求最小的石堆最大的石子数。
二分做,假设结果是 x,然后通过一遍拿石子的操作,最后判断石堆有没有小于 x 的,没有的话就扩大 x
反过来做需要注意一个问题,拿出的石子不是 (g[i]x) / 3【设 g 数组表示改变后的石堆石子数。】,而是 min(h[i]g[i]x) / 3,因为取出的石子数不会超过原有的石子数。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 2e5 + 10;
LL T = 1, n, h[N], g[N], l, r;
bool judge(LL x){
	for (int i = 1; i <= n; i++)
		g[i] = h[i];
	for (int i = n; i >= 3; i--){
		if (g[i] < x) return false;
		LL t = min(h[i], g[i] - x) / 3;
		g[i - 1] += t;
		g[i - 2] += 2 * t;
	}
	return g[1] >= x && g[2] >= x;
}
void solve(){
	scanf("%lld", &n);
	l = r = 1;
	for (int i = 1; i <= n; i++){
		scanf("%lld", &h[i]);
		r = max(r, h[i]);
	}
	while (l < r){
		LL mid = (l + r + 1) >> 1;
		if (judge(mid)) l = mid;
		else r = mid - 1;
	}
	cout << l << "\n";
}
int main(){
	cin >> T;
	while (T--)
		solve();
	return 0;
}

D. Robot Cleaner Revisit

题目大意:

A 一样,但是机器人每一次只会有 p100 的概率清洁所在行和列,求出机器人清洁掉污渍的时间。

思路:

设机器人移动到的位置次序为 id1,id2,id3,...,idk,在每一个位置开始移动的时候,机器人清洁的时间为 x1,x2,x3,...,xk
如果在 id2 的位置清洁了,那么 id1 的清洁时间就是 0,如果在 id2 没有清洁,那么 id1 的清洁时间就为 x2+1。可以得出关系式,x1=p(1+x2)
以此类推,可以得出某一个位置的清洁时间为 x=a1(1+a2(1+a3(1+...ak(1+x)..)))
就是一个线性关系,即 x=u+vx,转化一下,x=u1v
因为后面的值未知,前面的值就求不出来,所以要反着遍历,让刚开始的方向为 (-1, -1)就可以反向遍历了。
如果回到起点的话,总共 4nm 步,现在只做一个循环,所以总共遍历 4(n1)(m1) 次。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int mod = 1e9 + 7;
LL T, n, m, rb, cb, rd, cd, p;
LL qmi(LL a, LL k, LL p){
	LL ans = 1;
	while (k){
		if (k & 1) ans = ans * a % p;
		k >>= 1;
		a = a * a % p;
	}
	return ans;
}
LL inv(LL x){
	return qmi(x, mod - 2, mod);
}
void solve(){
	cin >> n >> m >> rb >> cb >> rd >> cd >> p;
	LL dx = -1, dy = -1, u = 0, v = 1;
	p = (100 - p) * inv(100) % mod;
	for (int i = 1; i <= 4 * (n - 1) * (m - 1); i ++ ){
		if (rb + dx < 1 || rb + dx > n) dx = - dx;
		if (cb + dy < 1 || cb + dy > m) dy = - dy;
		rb += dx;
		cb += dy;
		u = (u + 1) % mod;
		if (rb == rd || cb == cd){
			u = u * p % mod;
			v = v * p % mod;
		}
	}
	cout << (u * inv(1 - v) % mod + mod) % mod << "\n";
}
int main(){
	cin >> T;
	while ( T -- )
		solve();
	return 0;
}
posted on   Hamine  阅读(58)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

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