【C++】2024天梯赛补题题解

目录

L1部分

L1 - 1 编程解决一切

L1 - 2 再进去几个人

L1 - 3 帮助色盲

L1 - 4 四项全能

L1 - 5  别再来这么多猫娘了!

L1 - 6 兰州牛肉面

L1 - 7 整数的持续性

L1 - 8 九宫格

L2 部分

L2 - 1 鱼与熊掌

L2 - 2 懂蛇语

L2 - 3 满树的遍历

L2 - 4 吉利矩阵

L3部分

L3 - 1 夺宝大赛

L3 - 2 工业园区建设

L3 - 3 攀岩

已给出AC代码的题目如有不懂可在评论区提问哦,也欢迎大佬指错,或者提供更好的思路


L1部分

L1 - 1 编程解决一切

L1-097 编程解决一切 - 团体程序设计天梯赛-练习集 (pintia.cn)

00dc174a87bf4138b537b3f9bba3e598.png

L1 - 2 再进去几个人

L1-098 再进去几个人 - 团体程序设计天梯赛-练习集 (pintia.cn)

0d74b2a6ad8442b39aa33bdfca8c0676.png

#include<iostream>
using namespace std;
int main(){
    int a,b;cin >> a >> b;
    cout << b - a;
    return 0;
}

L1 - 3 帮助色盲

L1-099 帮助色盲 - 团体程序设计天梯赛-练习集 (pintia.cn)

a32908c44c1e43179e54abc208d68026.png

#include<iostream>
using namespace std;
int main(){
	int a,b;cin >> a >> b;
	if(b == 0){
		if(a == 0){
			cout << "biii" << endl;
			cout << "stop" << endl;
		}
		else if(a == 1){
			cout << "dudu" << endl;
			cout << "move" << endl;
		}
		else if(a == 2){
			cout << "-" << endl;
			cout << "stop" << endl;
		}
	}
	else if(b == 1){
		if(a == 0){
			cout << "-" << endl;
			cout << "stop" << endl;
		}
		else if(a == 1){
			cout << "-" << endl;
			cout << "move" << endl;
		}
		else if(a == 2){
			cout << "-" << endl;
			cout << "stop" << endl;
		}
	}
	return 0;
}

L1 - 4 四项全能

L1-100 四项全能 - 团体程序设计天梯赛-练习集 (pintia.cn)

cbd6b690beb441c9910c7ac79e3352b0.png

#include<iostream>
using namespace std;
int main(){
	int n,m;cin >> n >> m;
	int sum = 0;
	for(int i = 0;i < m;i++){
		int t;cin >> t;sum += t;
	}
    int tem = n * (m - 1);
	if(tem > sum)cout << "0" << endl;
    else cout << sum - tem << endl;
	return 0;
}

L1 - 5  别再来这么多猫娘了!

L1-101 别再来这么多猫娘了! - 团体程序设计天梯赛-练习集 (pintia.cn)

15ccfb2d3ded4fd2a4f3863aa471899f.png

易错:<censored> 也可能时违禁词....(家人们,谁懂啊~)

思路:把违禁词存起来,然后一个一个的去找。

#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
using namespace std;
vector<string> ban;
int main() {
	int n; cin >> n;
	getchar();
	string t;
	for (int i = 0; i < n; i++) {
		cin >> t; ban.push_back(t);
		getchar();
	}
	int tot; cin >> tot; getchar();
	string str; getline(cin, str);
	int c = 0;
    string l = "==========";            //用"......"可能不过
	for (int i = 0; i < ban.size(); i++) {
		int pos = str.find(ban[i]);
		while (pos != -1) {            //相同的屏蔽词可能出现不止一次
			str.replace(str.begin() + pos, str.begin() + pos + ban[i].length(), l);
			c++;
            pos = str.find(ban[i]);
		}
	}
	int pos = str.find(l);
	while (pos != -1) {
		str.replace(str.begin() + pos, str.begin() + pos + l.length(), "<censored>");
		pos = str.find(l);
	}

	if (c >= tot) {
		cout << c << endl;
		cout << "He Xie Ni Quan Jia!" << endl;
	}
	else {
		cout << str << endl;
	}
	return 0;
}

L1 - 6 兰州牛肉面

L1-102 兰州牛肉面 - 团体程序设计天梯赛-练习集 (pintia.cn)

7769db136cdc4ff78abcea31383f48db.png

#include<iostream>
#include<cstdio>
using namespace std;
double a[200][2];
int main(){
    int n;cin >> n;
    for(int i = 1;i <= n;i++){
    	cin >> a[i][0];
	}
	int p,b;
	while(cin >> p >> b && p && b){
		a[p][1] += b;
	}
	double sum = 0;
	for(int i = 1;i <= n;i++){
		printf("%.0lf\n",a[i][1]);
		sum += a[i][0] * a[i][1];
	}
	printf("%.2lf",sum);
    return 0;
}

L1 - 7 整数的持续性

L1-103 整数的持续性 - 团体程序设计天梯赛-练习集 (pintia.cn)

f0970cae6e1c4b3da81e69584babb8d2.png

应该没什么坑。。直接模拟

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int f(int x) {            //求下一个数
	int res = 1;
	while (x)res *= x % 10, x /= 10;
	return res;
}
vector<int> res;            //记录答案
int m;
int main() {
	int a, b; cin >> a >> b;
	for (int i = a; i <= b; i++) {
		int cnt = 0,t = i;
		while (t / 10) {        //如果是一个个位数,则跳出循环
			t = f(t);
			cnt++;
		}
		if (cnt > m) {
			res.clear();
			m = cnt;
			res.push_back(i);
		}
		else if (cnt == m) {
			res.push_back(i);
		}
	}
	cout << m << endl;
	for (int i = 0; i < res.size(); i++) {
		cout << res[i] << " \n"[i == res.size() - 1];
	}
	return 0;
}

L1 - 8 九宫格

L1-104 九宫格 - 团体程序设计天梯赛-练习集 (pintia.cn)

2d229afd477a49e69be977b151d54743.png

易错:输入不一定合法

难点:对于下标处理

思路:定义数组a[行][列],对行处理就像输入那样,对列处理把 i 和 j 的位置交换一下,

对于宫格的处理可以进行打表

#include<iostream>
#include<cstring>
using namespace std;
const int N = 11;
const int n = 9;
int a[N][N];
int vis[N];
int gp[3][2] = {{1,3},{4,6},{7,9}};
void solve(){
	int f = 1;			//标记该九宫格是否合法 
	for(int i = 1;i <= n;i++){
		memset(vis,0,sizeof(vis));
		for(int j = 1;j <= n;j++){
			cin >> a[i][j];
			if(a[i][j] >= 10 || a[i][j] <= 0){	//判断输入是否合法 
				f = 0;
				continue;		//防止在下面越界访问 
			}
			if(vis[a[i][j]])f = 0;			//判断每一行是否合法 
			else vis[a[i][j]] = 1;
		}
	}
	if(f){
		//判断每一列是否合法 
		for(int j = 1;j <= n;j++){
			memset(vis,0,sizeof(vis));
			for(int i = 1;i <= n;i++){
				if(vis[a[i][j]])f = 0;
				else vis[a[i][j]] = 1;
			}
		}
	}
	if(f){
		//判断每一宫格是否合法 
		for(int g = 0;g < n;g++){
			memset(vis,0,sizeof(vis));
			for(int i = gp[g / 3][0];i <= gp[g / 3][1];i++){
				for(int j = gp[g % 3][0];j <= gp[g % 3][1];j++){
					if(vis[a[i][j]]) f = 0;
					else vis[a[i][j]] = 1;
				}
			}
		}
	} 
	if(f)cout << "1" << endl;
	else cout << "0" << endl;
}

int main(){
	int t;cin >> t;
	while(t--){
		solve();
	}
	return 0;
}

L2 部分

L2 - 1 鱼与熊掌

L2-049 鱼与熊掌 - 团体程序设计天梯赛-练习集 (pintia.cn)

7059c41cb79d411dbdda3f64f6f77dca.png

易错:map或者set会超时

思路:一个unordered_map存一个人所持有的物品,然后暴力。。

#include<iostream>
#include<unordered_map>
#include<vector>
using namespace std;
const int N = 1e5 + 12;
unordered_map<int,int> a[N];
int main(){ 
	int n,m;cin >> n >> m;
	for(int i = 1;i <= n;i++){
		int k;cin >> k;
		for(int j = 0;j < k;j++){
			int t;cin >> t;
			a[i][t] = 1;
		}
	}
	int q;cin >> q;
	for(int i = 0;i < q;i++){
		int t1,t2;cin >> t1 >> t2;
		int res = 0;
		for(int j = 1;j <= n;j++){
			if(a[j].count(t1) && a[j].count(t2))res++;
		}
		cout << res << endl;
	}
	return 0;
}

L2 - 2 懂蛇语

L2-050 懂蛇语 - 团体程序设计天梯赛-练习集 (pintia.cn)

4cd1f7afed484e04b3819c8ea635f598.png

易错:1.字典中的句子可能以空格开头。

           2.字典中可能会有相同的句子。

思路:map<字典句子中每个字的首字母组成的字符串,句子的vector数组>,

及map<string,vector<string>>

#include<iostream>
#include<vector>                //不用set原因是会有相同的句子
#include<string>
#include<algorithm>
#include<cstdio>
#include<map>
using namespace std;
map<string, vector<string>> a;
string f(string str) {        //获取句子每个字的首字母
	string t;
	if(str[0] != ' ')t.push_back(str[0]);        //防止字典开头为空格
	for (int i = 0; i < str.length() - 1; i++) {
		if (str[i] == ' ' && str[i + 1] != ' ')t.push_back(str[i + 1]);
	}
	return t;
}
int main() {
	int n; cin >> n;getchar();
	for (int i = 1; i <= n; i++) {
		string tem;
		getline(cin, tem);
		string t = f(tem);
		a[t].push_back(tem);
	}
	int q; cin >> q;getchar();
	while(q--){
		string tem; getline(cin, tem);
		string t = f(tem);
		if (a.count(t)) {                           //看看字典中是否存在相应的句子
			string res;
			sort(a[t].begin(), a[t].end());        //排序不能忘
			for (auto j : a[t]) {
				res = res + j + "|";
			}
			res.pop_back();
			cout << res << endl;
		}
		else cout << tem << endl;
	}
	return 0;
}

L2 - 3 满树的遍历

L2-051 满树的遍历 - 团体程序设计天梯赛-练习集 (pintia.cn)

facb1fed96724d1a94b1700f338514fe.png

易错:1.不能用链式前向星

           2.当树中只有一个节点时,树的度为0

思路:用邻接表存树,从0开始dfs,存树时记录每个节点的度,找出最大的度,dfs时根据节点的度与最大度来判断是不是k阶满树。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 1e5 + 12;
int du[N];
vector<int> tree[N];
vector<int> res;
int deep,mdu;
int f = 1;
void dfs(int u){
	if(u != 0 && mdu != tree[u].size() && du[u] != 0)f = 0;
	res.push_back(u);            //先序存入当前访问节点
	for(int i = 0 ;i < tree[u].size();i++){
		int v = tree[u][i];
		dfs(v);
	}
}

int main(){
	int n;cin >> n;
	for(int i = 1;i <= n;i++){
		int t;cin >> t;tree[t].push_back(i);
		du[t]++;
		mdu = max(mdu,du[t]);
	}
	dfs(0);
	if(n == 1)cout << "0 ";                //如果树中只有一个节点,那么度为0
    else cout << mdu << " ";
	if(f)cout << "yes" << endl;
	else cout << "no" << endl;
	for(int i = 1;i < res.size();i++){
		cout << res[i] << " \n"[i == res.size() - 1];
	}
	return 0;
}

L2 - 4 吉利矩阵

L2-052 吉利矩阵 - 团体程序设计天梯赛-练习集 (pintia.cn)

e15963cbfe4548f58dc18f5b648a5dd4.png

思路:模拟填表,搜索枚举所有可能。

#include<iostream>
using namespace std;
const int N = 5;
int a[5][5];            //填表 a[行][列]
int l, n, cnt;
int cheakrow(int x) {       //检查行,求第x行的和
    int sum = 0;
    for (int i = 0; i < n; i++)sum += a[x][i];
    return sum;
}
int cheakcol(int x) {        //检查列,求第x列的和
    int sum = 0;
    for (int i = 0; i < n; i++)sum += a[i][x];
    return sum;
}
void dfs(int x,int y) {        
    if (x == n - 1 && y == n - 1) {
        cnt++;               //填表完成后记录
        return;    
    }
    //一行一行地填表格
    int dy = (y + 1) % N, dx = x + (y + 1) / N;
    //枚举表格中的所有可能
    for (int i = 0; i <= l; i++) {
        //边界检查
        if (y == n - 1 && cheakrow(x) + i != l)continue;    //x行填满,检查第x行
        if (x == n - 1 && cheakcol(y) + i != l)continue;    //y列填满,检查第y列
        //剪枝
        if (cheakcol(y) + i > l || cheakrow(x) + i > l)break;
        a[x][y] += i;        
        dfs(dx, dy);
        a[x][y] -= i;        //回溯
    }
}
int main() {
    cin >> l >> n;
    dfs(0, 0);
    cout << cnt << endl;
    return 0;
}

L3部分

L3 - 1 夺宝大赛

L3-037 夺宝大赛 - 团体程序设计天梯赛-练习集 (pintia.cn)

思路:以终点为起点,做bfs,并把各个位置到起点的距离记录下来,根据队员的坐标直接提取最短距离并记录下来,最后根据规定去输出结果

易错:1.坐标输入时要反一下

          2.bfs 对于标记的距离的时机有要求

曾尝试IDS但超时了...

#include<iostream>
#include<queue>
#include<map>
#include<vector>
#include<cstring>
using namespace std;
const int N = 123;
int a[N][N];
int vis[N][N];
int n, m, ex, ey;
int d[4][2] = { {1,0},{-1,0},{0,1},{0,-1} };
struct node { int x, y, t; };
map<int, vector<int>> res;            //map<到大本营的时间,该时间时到达的队伍编号>
int bfs(node s) {
	queue<node> q;
	q.push(s);
    vis[s.x][s.y] = s.t;
	while (!q.empty()) {
		node u = q.front(); q.pop();
        //在此处记录距离会导致同一个节点重复入队多次而导致内存超限
        //vis[u.x][u.y] = u.t; 
		for (int i = 0; i < 4; i++) {
			int dx = u.x + d[i][0], dy = u.y + d[i][1];
			if (dx < 1 || dy < 1 || dx > m || dy > n || a[dx][dy] == 0 || vis[dx][dy])continue;
            vis[dx][dy] = u.t + 1;        //在这里记录就可以避免内存超限
			q.push(node{ dx,dy,u.t + 1 });
		}
	}
	return -1;
}
int main() {
	cin >> m >> n;
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= n; j++) {
			cin >> a[i][j];
			if (a[i][j] == 2)ex = i, ey = j;        //找大本营的位置
		}
	}
	bfs(node{ ex,ey,1 });
	for (int i = 1; i <= m; i++) {                //把走不到的地方标记为-1
		for (int j = 1; j <= n; j++) {
			if (vis[i][j] == 0 && a[i][j] != 2)vis[i][j] = -1;
		}
	}
	int k; cin >> k;
	for (int i = 1; i <= k; i++) {
		int x, y; cin >> y >> x;        //这里要颠倒一下,仔细读题就会知道原因了
		int t = vis[x][y];
		if (t != -1)	res[t - 1].push_back(i);    由于实际t是从1开始记录的,所以这里减一
	}
	for (auto i : res) {
		if (i.second.size() == 1) {
			cout << i.second[0] << " " << i.first << endl;
			return 0;
		}
	}
	cout << "No winner." << endl;
	return 0;
}

L3 - 2 工业园区建设

L3-038 工业园区建设 - 团体程序设计天梯赛-练习集 (pintia.cn)

孩子正在补题....

L3 - 3 攀岩

L3-039 攀岩 - 团体程序设计天梯赛-练习集 (pintia.cn)

——题目过长无法展示——

孩子正在补题...

已给出AC代码的题目有不懂的可在评论区提问哦,也欢迎大佬指错,或者提供更好的思路

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

昕念丶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值