周赛 Round#2 题解

系列文章目录

1.周赛 Round#1 (2023/4/22)



前言

这是系列周赛的第二次,于5月13日8:30开始,12:00结束。
本次比赛一共有6道题,题目信息如下:

题目序号题目名称时间限制空间限制题目类型评测方式考查知识题目难度
1行走的机器人 robot1000ms256MiB传统题文本比较模拟/深搜中等
2多米诺骨牌涂色 paint2000ms256MiB传统题文本比较递推中等+
3最小得分 mex1000ms512MiB传统题文本比较中等+
4幸运数字 lucky2000ms512MiB传统题文本比较数论(gcd)
5无向图与函数 grafun1000ms512MiB传统题文本比较图论与前缀和
6最小子集 subset1000ms256MiB传统题文本比较二分图

T1 行走的机器人 robot

题目描述

Bob 对机器人进行了编程,让它在平面迷宫中行走。 迷宫有一些障碍。 空单元格由字符".“表示,障碍物由”#"表示。 迷宫中只有一个机器人。
它的起始位置用字符"S"表示。 这个位置没有任何障碍。 迷宫中也只有一个出口,用字符"E"表示。 这个位置没有任何障碍。
机器人只能向上、向左、向右或向下移动。 Bob 给机器人编程时,写下了一串整数,由其中若干个0,1,2,3组成。
他打算让每个数字对应一个不同的方向,机器人会按照指示到达出口。 不幸的是,他忘记了每个数字分配的是什么方向
机器人会自动将0,1,2,3随机映射到不同方向,然后按照给定的指令顺序进行操作。如果指令导致机器人离开迷宫边缘或撞到障碍物,机器人就会崩溃。如果机器人在任意时刻到达出口,那么机器人将停止且不执行后续指令。
Bob 想确定有多少种不同的方向映射方案能够将机器人到达出口

输入格式

第一行输入两个整数n 和m,表示迷宫行数和列数。
接下来的n行每行恰好包含m个字符,表示迷宫。
迷宫中的每个字符都是".“, “#”,“S"或"E”。
迷宫中将恰好有一个"S"和一个"E”。
最后一行将包含一个字符串s,表示给机器人的指令。

输出格式

输出一个整数,表示能够让机器人到达出口的方向映射方案数。

样例

样例输入1

5 6
. . . . .#
S . . . .#
.# . . . .
. # . . . .
. . . E . .
333300012

样例输出1

1

样例输入2

6 6
. . . . . .
. . . . . .
. .SE. .
. . . . . .
. . . . . .
. . . . . .
01232123212302123021

样例输出2

14

样例输入3

5 3
. . .
.S.
###
.E.
. . .
3

样例输出3

0

样例解释

样例说明1

只有一种映射方案:
0 ——> D, 1——> L, 2——> U, 3——> R;

其中D表示向下,L表示向左,U表示向上,R表示向右。

数据范围与提示

·2<=n,m<=50;
·1<=|s|<=100,其中|s|表示字符串s的长度
·对于任意的i,si为整数,且0<=si<=3;
·迷宫中的每个字符都是".“, “#”, “S"或"E”,且迷宫中有且仅有一个"S"和一个"E”。

题目分析

法一:模拟

思路:

一看样例,我们就知道这道题完全可以全排列出字符串所代表的意义的每一种情况。然后直接利用二维数组就行模拟。

代码结构:

1.主函数内完成输入二维数组,边输入边记录起点的位置。
2.进行全排列(可以在主函数内也可以再写一个函数)。
3.在fin函数内,根据排列的情况逐一将字符串与其对应:

if (s[i] - 48 == a) f++;
if (s[i] - 48 == b) ba++;
if (s[i] - 48 == c) f--;
if (s[i] - 48 == d) ba--;

注:此处的f代表横坐标,ba代表纵坐标(下文也一样)。
4.判断边界及是否到达终点,并返回至主函数。
5.主函数接收到返回值,改变sum的值。

注意:

1.输入时注意顺序,先输入数组再输入字符串(犯错人:zyc);
2.全排列注意边界及判断条件:(犯错人:lx)

for (int d = 0; d <= 3; d++) {
		for (int l = 0; l <= 3; l++) {
			if (l == d) continue;
			for (int u = 0; u <= 3; u++) {
				if (u == d || u == l) continue;
				for (int r = 0; r <= 3; r++) {
					if (r == d || r == l || r == u) continue;
					if (fin(d, l, u, r, fro, bac)) sum++;
				}
			}
		}
	}

3.注意判断边界:

if (f > n || f < 1 || ba > m || ba < 1) return 0;

4.注意循环内的循环变量不能和其他变量同名(犯错人:zyc).

代码:
#include <bits/stdc++.h>
using namespace std;
int n, m, fro, bac, sum;
string s;
char p[55][55];
bool fin(int a, int b, int c, int d, int f, int ba){
	for (int i = 0; i <= int(s.size()) - 1; i++) {
		if (s[i] - 48 == a) f++;
		if (s[i] - 48 == b) ba++;
		if (s[i] - 48 == c) f--;
		if (s[i] - 48 == d) ba--;
		if (p[f][ba] == '#') return 0;
		if (p[f][ba] == 'E') return 1;
		if (f > n || f < 1 || ba > m || ba < 1) return 0;
	}
	return 0;
}
int main() {
//	freopen("robot.in", "r", stdin);
//	freopen("robot.out", "w", stdout);
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> p[i][j];
			if (p[i][j] == 'S') fro = i, bac = j;
		}
	}
	cin >> s;
	for (int d = 0; d <= 3; d++) {
		for (int l = 0; l <= 3; l++) {
			if (l == d) continue;
			for (int u = 0; u <= 3; u++) {
				if (u == d || u == l) continue;
				for (int r = 0; r <= 3; r++) {
					if (r == d || r == l || r == u) continue;
					if (fin(d, l, u, r, fro, bac)) sum++;
				}
			}
		}
	}
	cout << sum;
	return 0; 
}

法二:深搜

T2 多米诺骨牌涂色 paint

T3 幸运数字 lucky

分析

看题可知,本题暴力枚举一定超时(不然怎么可能是第四题 )。这时,我们应该想到欧拉定理。

思路:

1.暴力枚举 期望得分:50pts。
2.令m=9*L/gcd(8,L),若gcd(10,m)!=1。无解。
3.枚举1~phi(m)因子,若d|phi(m)且10^d同余1模m,答案x=d(min),期望得分:70pts.
4.龟速乘。期望得分:100分。(主要防止超long long)。

代码:

1.gcd
ll gcd1(ll a, ll b) {   //辗转相除法
	ll r;
	while (b > 0) r = a % b, a = b, b = r;
	return a;
}
2.lucky
ll lucky() { //根据欧拉定理求最小值
	ll u = fai(m), ans = 0;
	for (ll i = 2; i * i <= u; i++ ) {
		//cout <<i ;
		if (u % i == 0) {
			if (_pow(10, i, m) == 1) return i;//单调递增,直接返回
			if (_pow(10, u / i, m) == 1) ans = u / i;//本来就是单调递减,所以不需要min函数
		}
	}
	return ans;
}
3.求phi
ll fai(ll m) {
	ll ans = m;
	for (ll i = 2; i * i <= m; i++)
		if (m % i == 0) {
			ans = ans / i * (i - 1);//1-1/pi
			while (m % i == 0) m /= i;
		}
	if (m > 1) ans = ans / m * (m - 1);
	return ans;
}
龟速乘
ll _pow(__int128 a, __int128 b, __int128 mod) {
	ll ans = 1;//注意是1不是0,不然23行是0*a
	while (b) {
		if (b & 1) ans = (ans * a) % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return ans;
}

__int128是什么?有什么用?什么时候用?

在最大值比long long 大一点点时使用。
INT_MAX = 2^(32-1)-1
LONG_LONG_MAX = 2^(64-1)-1
__int128极大值:2^(128-1)-1
注:__int128只能进行四则运算,不能用cin,cout输出。

总结

本次考试总结

得分分布

题目序号题目名称得分题目难度
1行走的机器人 robot100中等
2多米诺骨牌涂色 paint27中等+
3最小得分 mex0中等+
4幸运数字 lucky0
5无向图与函数 grafun0
6最小子集 subset11

反思

考试上的

1.还是有部分分该的没有得到,如第二题打表,情况考虑出现偏差,丢失:5-10分;
2.第四题的方法与题解上30pts的方法大同小异,丢失:50分,原因尚未找出(持续跟踪)。

学习上的

1.学过的知识不会举一反三,如第二题——递推。
2.知识面不宽,超前学习不够。如本系列第五题——图论,拿不到分,想有成绩上的突破就必须攻下它。

1.周赛系列第一、二题一般为模拟、递推或一些简单的算法。难度较低,目标得分:150+;
2.第三、四题多为更难的算法,如:DP、贪心、搜索等,目标得分:50+。
3.第五题考查知识点为图论,想要拿到此题的分就必须尽快学习图论的知识。
4.第六题一般为数论,难度极大,得分不易。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

来自八中的小鹿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值