【2021天梯赛】L2-L3补题记录

本文作者分享了首次参与编程天梯赛的体验,虽然感到比赛难度适中,但因一题卡关导致未能获得预期成绩。文章回顾了解题思路,包括病毒溯源、包装机、清点代码库、哲哲打游戏等题目,提供了C++代码解决方案,并对部分题目进行了策略分析和优化。此外,还提及了还原文件这一难题的解题策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

赛后感想

据说今年的天梯赛比以往简单,咱也不知道,没啥感觉,第一次参加天梯赛,所以并不晓得以往正式赛难度如何,反正我这次是失败告终了,难受啊,本来拿个个人三等应该是势在必得的,遇到病毒之后惨了,强行卡了一个多小时,斩获0分😶。哎,,不说了,都是辛酸泪啊。。。菜鸡流泪😭。

赛后补题

那就先来解决病毒溯源这个毒瘤吧。
看清题目,看清题目,看清题目。。。
ps:如果长链不唯一,输出最小序列

Problem 1 L2-038 病毒溯源(25)

补题传送门
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
解题思路:
就是直接暴力的思路。病毒源只有一个,可以记录顶点的度数来寻找病毒源。找到病毒源之后,用 B F S BFS BFS 求一个单源最长路即可。用 f a [ i ] fa[i] fa[i]数组来记录第 i i i 个节点的父亲节点。根据父亲节点与子节点之间的关系,逆向寻找路径,用二维 v e c t o r vector vector 数组记录所有可行方案,再来个排序输出第一个即为最终答案。

C++ AC代码:

#include<set>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
using namespace std;
vector<int> v[10010];
int d[10010], dist[10010], fa[10010];
vector<vector<int> > res;
int ans, root;
bool vis[10010];
void bfs()
{
	queue<int> q;
	q.push(root);
	dist[root] = 1;
	while (q.size())
	{
		int u = q.front();q.pop();
		for (int i = 0;i < v[u].size();i++)
		{
			int j = v[u][i];
			if (dist[j] < dist[u] + 1)
			{
				dist[j] = dist[u] + 1;
				fa[j] = u;
				q.push(j);
			}
		}
	}
}
bool cmp(vector<int> x, vector<int> y)
{
	for (int i = 0;i < x.size();i++)
	{
		if (x[i] != y[i]) return x[i] < y[i];
	}
}
int main()
{
	int n; scanf("%d", &n);
	for (int i = 0;i < n;i++)
	{
		int k; scanf("%d", &k);
		d[i]++;
		for (int j = 0;j < k;j++)
		{
			int x; scanf("%d", &x);
			v[i].push_back(x);
			d[x]++;
		}
	}
	while (d[root] != 1) root++;
	bfs();
	fa[root] = root;
	int pos;
	for (int i = 0;i < n;i++)
	{
		ans = max(ans, dist[i]);
	}
	printf("%d\n", ans);
	for (int i = 0;i < n;i++)
	{
		if (dist[i] == ans)
		{
			vector<int> tmp;
			int rt = i;
			while (fa[rt] != rt)
			{
				tmp.push_back(rt);
				rt = fa[rt];
			}
			tmp.push_back(root);
			reverse(tmp.begin(), tmp.end());
			res.push_back(tmp);
		}
	}
	sort(res.begin(), res.end(), cmp);
	for (int i = 0;i < res[0].size();i++)
	{
		printf("%d", res[0][i]);
		if (i < res[0].size() - 1) printf(" ");
	}
	return 0;
}

Problem 2 L2-037 包装机(25)

补题传送门
这个题是个简单的队列与栈的操作,不做过多解释,直接放上我的代码吧。

C++ AC代码

#include<set>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
using namespace std;
queue<char> q[110];
int op[100010];
char st[110];//框
int s;
int main()
{
	int N, M, S; cin >> N >> M >> S;
	for (int i = 1;i <= N;i++)
	{
		string str; cin >> str;
		for (int j = 0;j < str.size();j++) q[i].push(str[j]);
	}
	M = 0;
	while (1)
	{
		int x; cin >> x;
		if (x == -1) break;
		op[++M] = x;
	}
	vector<char> res;//传送带上物品
	for (int i = 1;i <= M;i++)
	{
		int k = op[i];
		if (k == 0)
		{
			if (s) res.push_back(st[s--]);
		}
		else {
			if (q[k].empty()) continue;
			if (s < S){
				st[++s] = q[k].front();q[k].pop();
			}
			else {
				res.push_back(st[s--]);
				st[++s] = q[k].front();q[k].pop();
			}
		}
	}
	for (int i = 0;i < res.size();i++)
	{
		cout << res[i];
	}
	return 0;
}

Problem 3 L2-039 清点代码库(25)

补题传送门
在这里插入图片描述
在这里插入图片描述
解题思路:
这个题还真就长见识了,两个 v e c t o r vector vector 容器可以直接比较大小,比较规则是从前往后遍历每一个元素,返回第一个不相等的元素的比较结果。可以放进 s e t set set 中,也可以放进 m a p map map 中。这样的话,就很好操做了。一开始我使用 m a p map map 记录出现的次数,利用 s e t set set 去重,但可能是卡 m a p map map 了,只能得到 21 21 21 分。得到满分的做法是先排序,相同的就会在相邻的位置,从前往后遍历,记录出现次数,用结构体存储可以比较方便的实现排序及计数。
注意:这个题会卡 c i n cin cin c o u t cout cout.

C++ Score 25:

#include<set>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
using namespace std;
vector<vector<int> > v;
struct node {
	int sum;
	vector<int> tmp;
}st[10010];
int s;
bool cmp(node x, node y)
{
	if (x.sum != y.sum) return x.sum > y.sum;
	else return x.tmp < y.tmp;
}
int main()
{
	int n, m; scanf("%d%d", &n, &m);
	for (int i = 0;i < n;i++)
	{
		vector<int> tmp;
		for (int j = 0;j < m;j++)
		{
			int x; scanf("%d", &x);
			tmp.push_back(x);
		}
		v.push_back(tmp);
	}
	sort(v.begin(), v.end());
	st[++s] = { 1,v[0] };
	for (int i = 1;i < n;i++)
	{
		if (v[i] != v[i - 1])
		{
			st[++s] = { 1,v[i] };
		}
		else st[s].sum++;
	}
	sort(st + 1, st + s + 1, cmp);
	printf("%d\n", s);
	for (int i = 1;i <= s;i++)
	{
		printf("%d", st[i].sum);
		for (int j = 0;j < st[i].tmp.size();j++)
		{
			printf(" %d", st[i].tmp[j]);
		}
		if (i < s) printf("\n");
	}
	return 0;
}

C++ Score 21:

#include<set>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
using namespace std;
vector<int> v[10010];
map<vector<int>, int> mp;
set<vector<int> > s;
bool cmp(vector<int> x, vector<int> y)
{
	if (mp[x] != mp[y]) return mp[x] > mp[y];
	return x < y;
}
int main()
{
	int n, m; scanf("%d%d",&n,&m);
	for (int i = 0;i < n;i++)
	{
		for (int j = 0;j < m;j++)
		{
			int x; scanf("%d",&x);
			v[i].push_back(x);
		}
		mp[v[i]]++;
		s.insert(v[i]);
	}
	vector<vector<int> > res;
	for (auto item : s) {
		res.push_back(item);
	}
	sort(res.begin(), res.end(), cmp);
	/*for (int i = 0;i < res.size();i++)
	{
		for (int j = 0;j < res[i].size();j++)
		{
			cout << res[i][j] << " ";
		}
		cout << endl;
	}*/
	printf("%d\n",res.size());
	for (int i = 0;i < res.size();i++)
	{
		printf("%d",mp[res[i]]);
		for (int j = 0;j < res[i].size();j++)
		{
			printf(" %d",res[i][j]);
		}
		if (i < res.size() - 1) printf("\n");
	}
	return 0;
}

Problem 4 L2-040 哲哲打游戏(25)

补题传送门
阅读理解题,按照题目描述模拟就OK,so easy 呀。无语了,当时就应该先开这个题的,策略问题,当时看到题目描述有点长,就习惯性的略过了,直接留到了后面,然而到后面之后根本没心思冷静下来读题,难受。

C++ Score 25:

#include<set>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
using namespace std;
const int N = 100010;
vector<int> v[N];
int mark[N];
int main()
{
	int n, m; scanf("%d%d", &n, &m);
	for (int i = 1;i <= n;i++)
	{
		int k; scanf("%d", &k);
		v[i].push_back(0);
		for (int j = 1;j <= k;j++)
		{
			int x;scanf("%d", &x);
			v[i].push_back(x);
		}
	}
	int now = 1;
	while (m--)
	{
		int op, x; scanf("%d%d", &op, &x);
		if (op == 1)
		{
			mark[x] = now;
			printf("%d\n",mark[x]);
		}
		else if(op == 0){
			now = v[now][x];
		}
		else if (op == 2)
		{
			now = mark[x];
		}
	}
	printf("%d", now);
	return 0;
}

Problem 5 L3-029 还原文件(30)

补题传送门
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
解题思路:
1、非满分做法,直接暴力,就像字符串匹配那样,只要遇到第一个与当前纸片匹配的片段,就记录一下匹配的位置。之后按照位置排序,输出即可,骗分大法好,这样暴力直接白嫖26分,也是蛮不错滴。
2、满分做法真的没想到,竟然可以直接爆搜,而且还是跑的非常快的那种。听了y总的直播讲解后,恍然大悟啊。数据范围不是很大,有且仅存在一个解,所以直接 d f s dfs dfs 搜索即可,若当前片段能够和原串匹配,记录位置,搜索下一个片段。快速判断两个片段是否匹配时,需要用到字符串哈希的知识。代码实现不算很难,下面放上我的30分代码。

C++ Score 30:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef unsigned long long ull;
const int N = 100010,M = 110;
const int P = 131;
ull h[N],p[N];
ull g[M];//存储m个小碎片的哈希值
int width[M];//存储小碎片的宽度
int n,m;
ull get_hash(int l,int r)
{
    return h[r] - h[l - 1] * p[r - l + 1];
}
bool vis[N];
int ans[M];
void dfs(int t,int start)//开始匹配的起点
{
    if(t > m){
        for(int i = 1;i <= m;i++)
        {
            printf("%d",ans[i]);
            if(i < m) printf(" ");
        }
        return;
    }
    for(int i = 1;i <= m;i++)
    {
        if(!vis[i] && g[i] == get_hash(start,start + width[i] - 1))
        {
            vis[i] = true;
            ans[t] = i;
            dfs(t + 1,start + width[i] - 1);
            vis[i] = false;
            ans[t] = 0;
        }
    }
}
int main()
{
    p[0] = 1;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)
    {
        int x; scanf("%d",&x);
        p[i] = p[i - 1] * P;
        h[i] = h[i - 1] * P + x + 1;
    }
    scanf("%d",&m);
    for(int i = 1;i <= m;i++)
    {
        int len; scanf("%d",&len);
        width[i] = len;
        for(int j = 1;j <= len;j++)
        {
            int x; scanf("%d",&x);
            g[i] = g[i] * P + x + 1;
        }
    }
    dfs(1,1);
    return 0;
}

C++ Score 26:

#include<set>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
using namespace std;
const int N = 100010;
int a[N], n;
struct node {
	int id;
	int xh;
	vector<int> v;
}st[N];
void deal(node& x)
{
	for (int i = x.v.size();i <= n;i++)
	{
		bool flag = true;
		for (int j = 0;j < x.v.size();j++)
		{
			if (x.v[j] != a[i - x.v.size() + j + 1])
			{
				flag = false;
				break;
			}
		}
		if (flag)
		{
			x.id = i;
			return;
		}
	}
}
bool cmp(node x, node y)
{
	return x.id < y.id;
}
int main()
{
	scanf("%d", &n);
	for (int i = 1;i <= n;i++) scanf("%d", &a[i]);
	int m; scanf("%d", &m);
	for (int i = 1;i <= m;i++)
	{
		int num; scanf("%d", &num);
		vector<int> tmp;
		for (int j = 1;j <= num;j++)
		{
			int x; scanf("%d", &x);
			tmp.push_back(x);
		}
		st[i] = { i,i,tmp };
		deal(st[i]);
	}
	sort(st + 1, st + m + 1, cmp);
	for (int i = 1;i <= m;i++)
	{
		printf("%d", st[i].xh);
		if (i < m) printf(" ");
	}
	return 0;
}

更新ing。。。
最近更新时间:2021.4.29.00:11✌

<think>好的,我现在需要帮助用户查询团队天梯赛L2-001题目的相关信息或解题思路。首先,我要确认用户提到的L2-001具体是哪一的题目,因为不同份的题目内容可能不同。用户之前提供的引用内容是关于2021天梯赛的L1题,但用户现在询问的是L2级别的题目,可能需要更多的信息。 由于用户提供的引用中并没有直接提到L2-001,我需要依靠自己的知识库或查找相关资源。根据常见的L2题目结构,L2-001通常涉及较为复杂的算法或数据结构,比如最短路、动态规划、树结构等。例如,有的份的L2-001可能是关于紧急救援的问题,涉及Dijkstra算法的应用。 接下来,我需要验证这个假设是否正确。假设题目是紧急救援类问题,通常要求计算最短路径的数量,并在最短路径中选择救援队伍数量最多的路径。解题思路一般包括使用Dijkstra算法,同时维护两个数组:一个记最短距离,另一个记最大救援队数量,以及路径数量。 然后,我需要考虑如何结构化回答。首先给出题目的大致描述,然后分步骤解析解题思路,包括图的建立、Dijkstra算法的应用、状态更新的条件等。接着提供示例代码,并确保代码符合用户之前的格式要求,如Python代码块,并正确使用LaTeX公式。 另外,用户要求生成相关问题,我需要根据题目内容提出可能的相关问题,例如如何优化Dijkstra算法、如何处理多个最短路径的情况,以及题目的应用场景等。 最后,检查所有LaTeX公式是否正确使用$...$和$$...$$格式,确保没有语法错误,并确认回答结构清晰,符合用户的要求。</think>### 团队天梯赛 L2-001 紧急救援 题目解析 L2-001通常为**城市紧急救援**类题目,要求计算最短路径数量及最大救援队伍。以下是解题思路: #### 1. 题目核心要素 - 城市构成带权无向图,节点表示城市,边权为路径长度 - 每个城市有救援队伍数量 - 需求:从起点到终点的 - 最短路径条数 - 最短路径中能集结的最大救援队伍 - 具体路径输出 #### 2. 算法选择 采用**Dijkstra算法**变体,维护三个状态数组: - $dist[]$: 最短距离 - $num[]$: 路径数量 - $teams[]$: 最大救援队 - $pre[]$: 前驱节点(用于回溯路径) #### 3. 实现步骤 1. **建图** - 使用邻接表存储:`vector<pair<int, int>> graph[N]` -各城市初始救援队数量 2. **优先队列优化** ```cpp priority_queue<PII, vector<PII>, greater<PII>> pq; // 小顶堆 ``` 3. **状态更新规则** - 当发现更短路径时: $$ dist[v] = dist[u] + w $$ $$ num[v] = num[u] $$ $$ teams[v] = teams[u] + city_teams[v] $$ - 当路径长度相等时: $$ num[v] += num[u] $$ $$ if(teams[u] + city_teams[v] > teams[v]) $$ $$ \quad update\ teams[v]\ and\ pre[v] $$ #### 4. 复杂度分析 - 时间复杂度:$O(M + NlogN)$(优先队列优化版Dijkstra) - 空间复杂度:$O(N+M)$ #### 示例代码框架(C++) ```cpp #include <bits/stdc++.h> using namespace std; const int N=510; int city_teams[N], dist[N], num[N], teams[N], pre[N]; vector<pair<int,int>> graph[N]; void dijkstra(int s, int n){ fill(dist, dist+N, INT_MAX); dist[s] = 0; num[s] = 1; teams[s] = city_teams[s]; // ... 优先队列实现 } void print_path(int v){ if(v == pre[v]) return; print_path(pre[v]); cout << v << " "; } ```
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值