本次比赛我个人得分距离 175 分线仅差数分,主要失分点在 L2-1 卡点未全过、L2-4 发挥失误未能完赛,最终依靠队友的稳定发挥,团队拿下了全国三等奖。 本文侧重梳理题目思路、应试技巧与备赛经验,重点详解 L2 部分,L3 将在后续更新补充。
文章目录
-
- 小技巧
-
- 1. vector 带空格标准输出模板
- 2. 整行输入必掌握:getline
- L1 题目复盘与考点总结
- L2 题目详解(重点)
-
- L2-1 栈模拟大题
- L2-2 枚举 + 二分查询题
- L2-3 树的 DFS 最大路径最小值
- L2-4 排序 + DFS 题
- 备赛经验与刷题建议
PTA官网真题:https://pintia.cn/problem-sets/994805046380707840/exam/problems/type/7
小技巧
PTA 平台对输出格式的要求极其严格,空格、换行的细微偏差都会直接导致测试点不通过,这里分享两个考场高频使用的实用模板与细节:
1. vector 带空格标准输出模板
针对「元素间用空格分隔、行末不能有多余空格」的经典输出场景,最稳妥且不易出错的写法如下:
vector<int>ans;
for (int i = 0; i < int(ans.size()); ++i) {
if (i) cout << ' ';
cout << ans[i];
}
关键细节提醒:vector.size() 的返回值是无符号类型 size_t,直接参与运算或比较时,边界场景下可能出现隐式转换异常。务必先用 int 强转后再使用,避免因类型问题产生难以排查的 bug。
2. 整行输入必掌握:getline
PTA 的字符串类题目频繁出现含空格的整行输入,仅用 cin 读取会因空格截断导致逻辑完全错误。本次 L1-6 我就踩了这个坑,卡了近 20 分钟才反应过来,改用 getline 后直接通过。 备赛阶段一定要熟练掌握 getline 的用法,以及它与 cin 混用时的换行符残留处理cin.ignore(),这是 L1-L2 都高频出现的考点。
L1 题目复盘与考点总结
L1 整体以基础语法和简单模拟为主,难度偏低,这里仅提炼需要注意的题目与考点:
L1-1 ~ L1-5:均为基础送分题,考察基本输入输出、简单运算与基础逻辑,正常备赛都能快速通关。 无代码 L1-6:字符串输入易错题,核心坑点是含空格的整行输入处理,熟练使用 getline 即可快速解决。 正解
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main() {
string s;
int t=11;
while(t—){
getline(cin,s);
cout<<s.size();
}
return 0;
}
L1-7:纯模拟送分题,严格按照题目描述的步骤实现即可,不涉及复杂算法。 正解
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main() {
int n;
cin >> n;
vector<int> a(n);
long long sum = 0;
int ma = –1, mi = 1e7;
for (int i = 0; i < n; ++i) {
cin >> a[i];
sum += a[i];
ma = max(ma , a[i]);
mi = min(mi , a[i]);
}
int avg = sum / n;
vector<int> ans;
for (int i = 0; i < n; ++i) {
if(a[i]>avg*2)ans.push_back(i+1);
}
// 第一行:最大值、最小值、平均值
cout << ma <<' '<< mi <<' '<< avg << '\\n';
// 第二行
if (ans.empty()) {
cout << "Normal\\n";
}
else {
for (int i = 0; i <(int)ans.size(); ++i) {
if (i) cout <<' ';
cout << ans[i];
}
cout << '\\n';
}
return 0;
}
L1-8:字符串操作题,考点与去年 L1 的一道真题完全重合,难度甚至更低;在官方准考证对应的模拟赛中l1-8题目中明确说明l1-8将要考去年一样的字符串考点。核心考察字符串的插入、查找、翻转与 substr 截取函数,赛前刷过历年题、认真打模拟赛的话,这道题属于必拿分。 正解
#include<bits/stdc++.h>
using namespace std;
string s;
int main(){
int n,op,len;
cin>>n>>s;
for(int i=0;i<n;i++){
cin>>op;
if(op==1){
string s1;
cin>>s1;
len=s1.size();
if(s.find(s1)==–1){
cout<<–1<<'\\n';
continue;
}
int cnt=0;
vector<int>ans;
for(int i=0;i+len<=s.size();i++){
if(s.substr(i,len)==s1){
cnt++;
ans.push_back(i);
if(cnt==3)break;
}
}
for(int i=0;i<cnt;i++){
if(i)cout<<' ';
cout<<ans[i];
}
cout<<'\\n';
}
else if(op==2){
int p;
string s2;
cin>>p>>s2;
if(p==s.size())s+=s2;
else{
string tmp="";
tmp+=s.substr(0,p);
tmp+=s2;
tmp+=s.substr(p);
s=tmp;
}
cout<<s<<'\\n';
}
else {
int l,r;
cin>>l>>r;
string tmp="",s2;
tmp+=s.substr(0,l);
s2=s.substr(l,r–l+1);
reverse(s2.begin(),s2.end());
tmp+=s2;
tmp+=s.substr(r+1);
s=tmp;
cout<<s<<'\\n';
}
}
return 0;
}
L2 题目详解(重点)
L2 是天梯赛拉开分差的核心区间,也是备赛的重中之重,下面逐题拆解解题思路、考场实战与踩坑点:
L2-1 栈模拟大题
这道题是我个人认为本次 L2 中编码复杂度最高的一题,属于思路简单、代码难实现题。
考点预判:历年 L2 中栈的考察频率极高,读完题目逻辑后我第一时间确定用栈实现,思路方向完全正确。 实战情况:实际编码 + 调试花费了 1 个多小时,题目细节和边界条件非常多,反复调试后仍有少量测试用例未通过,最终卡点失分。 备考建议:这类大模拟题没有捷径,只能靠平时多刷同类型题目,积累边界处理经验,提升代码一次成型的准确度,避免在考场上消耗过多调试时间,挤压后面题目的作答空间。 正解
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, T;
cin >> n >> T;
vector<int> c(n);
for (int i = 0; i < n; ++i) cin >> c[i];
// 用vector模拟栈,初始按自顶向下顺序压入(编号1在最上面)
vector<pair<int, int>> v; // {混乱指数, 编号}
for (int i = n – 1; i >= 0; —i) {
v.push_back({c[i], i + 1});
}
vector<pair<int, int>> left; // 临时存放混乱指数 > T 的作业
vector<int> ans; // 批改顺序
while (!v.empty() || !left.empty()) {
// 批改当前堆
while (!v.empty()) {
auto [val, idx] = v.back();
v.pop_back();
if (val > T) {
left.push_back({val, idx});
} else {
ans.push_back(idx);
}
}
// 当前堆为空,检查左手边是否有作业
if (left.empty()) break;
// 更新阈值为左手边混乱指数的平均值(向下取整)
int sum = 0;
for (auto p : left) sum += p.first;
T = sum / (int)left.size();
// 将左手边堆转为当前堆
v = move(left);
left.clear();
}
// 输出批改顺序
for (int i = 0; i <int(ans.size()); ++i) {
if (i) cout << ' ';
cout << ans[i];
}
cout << endl;
return 0;
}
L2-2 枚举 + 二分查询题
标准送分题,难度很低,核心是用预处理优化查询效率:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n + 1);
vector<int> v; // 中间值:存储所有分数,排序去重后用于二分查找
map<int, int> d; // 每种分数对应的最小编号
int mx = –1;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
mx = max(mx, a[i]);
v.push_back(a[i]);
// 同一种分数保留最小编号
d.emplace(a[i], i);
}
// 第一行:输出所有最高分对应的编号
bool first = true;
for (int i = 1; i <= n; ++i) {
if (a[i] == mx) {
if (!first) cout << ' ';
cout << i;
first = false;
}
}
cout << '\\n';
// 排序去重,用于 upper_bound 查找
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
int m;
cin >> m;
while (m—) {
int x;
cin >> x;
auto it = upper_bound(v.begin(), v.end(), x);
if (it == v.end()) {
cout << 0 << '\\n'; // 样例中无解输出 0
} else {
cout << d[*it] << '\\n';
}
}
return 0;
}
L2-3 树的 DFS 最大路径最小值
本题题干描述非常绕,直接通读很容易被迷惑,推荐「先看样例、画图推导」的方式快速破题。
题意转化 + 样例推导
题目中的「宝藏地」本质就是树的叶子节点。以样例为例,共 4 个叶子节点(宝藏地),从根节点 0 出发到各叶子的路径,以及路径上的最小边权如下:
- 路径 0→3:路径上的最小边权为 0
- 路径 0→2→6:路径上的最小边权为 10
- 路径 0→1→5→8:路径上的最小边权为 10
- 路径 0→1→4→7:路径上的最小边权为 8
题目要求的「最大的最小值」,就是在所有叶子节点的路径最小值中取最大值,对应样例答案为 10。 解法思路
用 DFS 遍历整棵树,同步维护一个辅助数组 / 变量,记录从根节点 0 到达当前节点的过程中,路径上的最小边权;遍历完成后,枚举所有叶子节点对应的最小值,取其中最大值即为答案。 整体逻辑非常清晰,属于「看懂题意就会做」的题目,关键是不要被冗长的题干劝退,结合样例画图拆解是最高效的破题方式。 正解
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
vector<pair<int, int>> g[N];
int a[N];
void dfs(int now, int fa,int mi){
a[now]=mi;
for (auto [nt,w]: g[now]) {
if(nt!=fa)dfs(nt,now,min(mi,w));
}
}
int main() {
int n;
cin >> n;
for (int i = 1; i < n ; ++i) {
int fa, w;
cin >> fa >> w;
g[i].push_back({fa,w});
g[fa].push_back({i,w});
}
//权值最大为100 110初始化
dfs(0,–1,110);
int ans = –1;
for (int i = 1; i < n ; ++i) {
//叶子节点
if(g[i].size()==1)ans=max(ans,a[i]);
}
vector<int>res;
for (int i = 1; i < n ; ++i) {
//叶子节点
if(g[i].size()==1&&a[i]==ans)
res.push_back(i);
}
sort(res.begin(),res.end());
cout<<ans<<'\\n';
for(int i=0;i<int(res.size());i++){
if(i)cout<<' ';
cout<<res[i];
}
return 0;
}
L2-4 排序 + DFS 题
这道题我发挥失误,考试只剩 20 分钟才开始作答,心态急躁导致出现段错误,最终没能调试通过,非常可惜。
核心思路:用 vector 嵌套结构体存储数据,先按照题目要求的规则排序,再用 DFS 遍历搜索符合条件的结果即可,属于 L2 的常规考法。 踩坑提醒:DFS 类题目一定要注意数组边界、递归终止条件,时间越紧张越容易出现越界、漏判断等低级错误。 正解
#include<bits/stdc++.h>
using namespace std;
const int N=10010;
bool vis[N];
struct nd{
int nt,p;
};
bool cmp(nd n1,nd n2){
if(n1.p!=n2.p)return n1.p>n2.p;
return n1.nt<n2.nt;
}
vector<nd>g[N];
vector<int>ans;
int n,m,k,t;
void dfs(int now){
ans.push_back(now);
for(auto [nt,p]:g[now]){
if(!vis[nt]){
vis[nt]=1;
dfs(nt);
break;
}
}
}
int main(){
cin>>n>>m;
for(int i=0;i<m;i++){
int u,v,p;
cin>>u>>v>>p;
g[u].push_back({v,p});
}
for(int i=1;i<=n;i++){
sort(g[i].begin(),g[i].end(),cmp);
}
cin>>k;
while(k—){
memset(vis,0,sizeof vis);
int st;
ans.clear();
cin>>st;
vis[st]=1;
dfs(st);
for(int i=0;i<(int)ans.size();i++){
if(i)cout<<"->";
cout<<ans[i];
}
cout<<'\\n';
}
return 0;
}
网硕互联帮助中心



评论前必须登录!
注册