这是我首次参加天梯赛的完整复盘,当时算法基础尚薄弱,解题节奏偏慢,加上当年 L1 难度整体高于 2026 年,最终 L1 有 1 题未完成、2 题靠暴力解法拿部分分;L2 仅 2 题通过暴力与特判拿到少量分数,其余题目0分,最终总分 107 分。作为首战成绩,当时已达到自己的预期。 2026 年我第二次参赛,最终获得 172 分、团体国家级三等奖。关于 2026 年的详细题解与备赛路线,可参考我的另一篇博客;
文章目录
-
- 小技巧
-
- 1. vector 带空格标准输出模板
- 2. 整行输入必掌握:getline(25年没考)
- L1 题目复盘与考点总结
-
- L1-6这不是字符串题
- L1-7大幂数
- L1-8现代战争
- L2 题目详解(重点)
-
- L2-1 算式拆解
- L2-2 三点共线
- L2-3 胖达的山头
- L2-4 被n整除的n位数
- 备赛经验与刷题建议
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(25年没考)
PTA 的字符串类题目频繁出现含空格的整行输入,仅用 cin 读取会因空格截断导致逻辑完全错误。本次 L1-6 我就踩了这个坑,卡了近 20 分钟才反应过来,改用 getline 后直接通过。 备赛阶段一定要熟练掌握 getline 的用法,以及它与 cin 混用时的换行符残留处理cin.ignore(),这是 L1-L2 都高频出现的考点。
L1 题目复盘与考点总结
L1 整体以基础语法、简单模拟为核心,难度偏低。
L1-1 ~ L1-3:送分题,正常备赛都能快速通关。 无代码 L1-4:按题目要求做就行
#include<bits/stdc++.h>
#define int long long
using namespace std;
int a[32];
signed main(){
int n;
cin>>n;
a[0]=1;
for(int i=1;i<32;i++){
a[i]=a[i–1]*2;
}
for(int i=31;i>=0;i—){
if(a[i]<=n){
cout<<a[i];
return 0;
}
}
return 0;
}
L1-5:按题目要求做就行
#include<bits/stdc++.h>
#define int long long
using namespace std;
int a[27],ans,cnt[27];
string s;
signed main(){
cin>>s;
for(int i=1;i<=26;i++)cin>>a[i];
for(int i=0;i<s.size();i++){
char c=s[i];
cnt[c–'a'+1]++;
ans+=a[c–'a'+1];
}
for(int i=1;i<=26;i++){
if(i>1)cout<<' ';
cout<<cnt[i];
}
cout<<'\\n'<<ans;
return 0;
}
L1-6这不是字符串题
这道题具有较强的迷惑性,表面看似非字符串题型,本质仍是经典字符串操作题。我当时被题目欺骗,没有往转字符串这方面考虑。
思路是做转换:将数字映射为字母,把数值数组转化为字符串后,即可用字符串操作完成题目要求,最终再映射回数字形式。 核心考点覆盖字符串三大基础操作:翻转(reverse)、查找(find)、截取(substr)。26年又考了重复考点,属于必会题 正解
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+9;
int n,m,t,ans;
string s;
int main(){
cin>>n>>m;
s+="";
for(int i=0;i<n;i++){
int x;
cin>>x;
s+=x+'a'–1;
}
while(m—)
{
int op;
cin>>op;
if(op==1)
{
int l1,l2;
string s1="",s2="";
cin>>l1;
for(int i=0;i<l1;i++){
int x;
cin>>x;
s1+=x+'a'–1;
}
cin>>l2;
for(int i=0;i<l2;i++){
int x;
cin>>x;
s2+=x+'a'–1;
}
if(s.find(s1)!=–1){
int pos=s.find(s1);
s.replace(pos,l1,s2);
}
}
else if(op==2){
string tmp="";
tmp+=s[0];
for(int i=1;i<s.size();i++){
int x1=(int)(s[i]+s[i–1]);
if(x1%2==0)tmp+=char(x1/2);
tmp+=s[i];
}
s=tmp;
}
else if(op==3){
int l,r;
cin>>l>>r;
string tmp="",s1,s2;
s1=s.substr(l–1,r–l+1);
reverse(s1.begin(),s1.end());
tmp+=s.substr(0,l–1);
tmp+=s1;
tmp+=s.substr(r);
s=tmp;
}
}
for(int i=0;i<s.size();i++){
cout<<s[i]–'a'+1;
if(i!=s.size()–1)cout<<' ';
}
return 0;
}
L1-7大幂数
核心解法为枚举次幂,可通过数学推导缩小枚举范围做简单优化。 题目中 n 的上限不超过 2^31,因此幂次枚举存在明确上界:当幂次为 1 时,由求和公式 m*(m+1)/2 可估算,m 取 2^15 时结果仍小于 n 上限,m 取 2^16 时则超出范围,因此枚举上界可设为 2^16。同时在累加过程中,若当前和已超过 n 可直接终止循环,进一步降低时间消耗。 正解
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+9;
int n,t,ans,a[N];
int mx1=1<<16;
int main(){
cin>>n;
int ansk,ansmx;
bool fd=0;
for(int i=1;i<=mx1;i++)a[i]=i;
for(int k=1;k<=31;k++)
{
int cnt=0;
for(int i=1;i<=mx1;i++)
{
cnt+=a[i];
a[i]*=i;
if(cnt==n)
{
fd=1;
ansk=k;
ansmx=i;
break;
}
if(cnt>n)break;
}
}
if(!fd)cout<<"Impossible for "<<n<<".";
else{
for(int i=1;i<=ansmx;i++){
cout<<i<<"^"<<ansk;
if(i!=ansmx)cout<<"+";
}
}
return 0;
}
L1-8现代战争
暴力思路为每次轰炸时遍历全部元素寻找最大值执行操作,该写法会因时间复杂度过高超时,我考场上靠暴力拿到 14 分。 正解采用优先队列(大顶堆)优化,利用堆结构 O (1) 取最大值,替代每次遍历找最大值的 O (n) 操作,即可满足时间限制。 正解
#include<bits/stdc++.h>
#define int long long
#define pii pair<int,int>
using namespace std;
const int N=1e3+9;
int g[N][N],t,x,n,m,k,r[1001],c[1001];
void zha(int h,int l){
r[h]=1;
c[l]=1;
}
signed main(){
priority_queue<pair<int,pii>,vector<pair<int,pii>>>q;
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
cin>>g[i][j];
q.push({g[i][j],{i,j}});
}
int cnt=0;
while(q.size()&&cnt<k){
auto [d,t]=q.top();q.pop();
auto [x,y]=t;
if(r[x]||c[y])continue;
else {zha(x,y);cnt++;}
}
int mxl=0;
set<int>s1,s2;
for(int i=1;i<=n;i++)
if(!r[i])s1.insert(i);
for(int i=1;i<=m;i++)
if(!c[i]){mxl=i;s2.insert(i);}
for(auto i:s1){
for(auto j:s2){
cout<<g[i][j];
if(j!=mxl)cout<<' ';
}
cout<<'\\n';
}
return 0;
}
L2 题目详解(重点)
L2 是拉开分差的核心区间,也是备赛的重中之重,以下逐题拆解考点与解题思路。
L2-1 算式拆解
栈模拟 这是一道典型的栈模拟大题,只要能识别出 “表达式处理→栈” 的模型,实现难度并不高。我当时未能想到,最终本题得 0 分。 栈是天梯赛 L2 的高频考点,2026 年赛事同样考察了栈相关题型,属于 L2 阶段必须熟练掌握的核心知识点
正解
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+9;
int n,t,ans;
stack<char>st;
int main(){
string s;
cin>>s;
for(int i=0;i<s.size();i++)
{
if(s[i]==')')
{
string tmp="";
while(st.top()!='(')
{
tmp+=st.top();
st.pop();
}
reverse(tmp.begin(),tmp.end());
cout<<tmp<<'\\n';
st.pop();
}
else st.push(s[i]);
}
return 0;
}
L2-2 三点共线
偏思维题 这是一道偏数学思维的题目,核心突破口在于利用题目限定条件简化问题。 题目中点的纵坐标仅有 3 种取值,因此可以按纵坐标分类,存储对应横坐标的集合。 根据三点共线的数学性质:若点 (x0,0)、(x1,1)、(x2,2) 共线,则满足x0+x2=2*x1。 基于该性质,只需枚举其中两类点的横坐标,推导第三类点的目标值,判断其是否存在即可。 实现时有两个细节需要注意:一是存在重复点,需先对横坐标集合去重;二是横坐标可能为负值,我当时采用了坐标偏移的方式将其全部转为正数处理,对结果无影响,也可直接用支持负数的存储结构实现。 正解
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9,P=3e6+9;
int n,t,ans;
bool st[6*P];
int main(){
int n;
cin>>n;
vector<int>v0;
vector<int>v1;
for(int i=0;i<n;i++){
int x,y;
cin>>x>>y;
if(y==0)v0.push_back(x);
if(y==1)v1.push_back(x);
if(y==2)st[P+x]=1;
}
sort(v0.begin(),v0.end());
sort(v1.begin(),v1.end());
v0.erase(unique(v0.begin(),v0.end()),v0.end());
v1.erase(unique(v1.begin(),v1.end()),v1.end());
bool fd=0;
for(auto x1:v1)
for(auto x0:v0){
if(st[P+2*x1–x0]){
fd=1;
printf("[%d, 0] [%d, 1] [%d, 2]\\n",x0,x1,2*x1–x0);
}
}
if(!fd)cout<<–1;
return 0;
}
L2-3 胖达的山头
区间差分模板题 考场上我没有看出来是差分题。但是注意到输出很简单,可以骗分直接输出一个数,从0到10几一个个试试,发现输出11能得13分!就这样考场上我骗到了13分
本题正解是差分的标准应用场景:每只熊猫的活跃时间对应一个区间 [l, r],通过差分数组 d [l]++、d [r+1]– 标记区间,最后求前缀和即可得到每个时间点的活跃熊猫数量,遍历取最大值即为答案。
正解
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
int d[N],n;
int main(){
cin>>n;
for(int i=0;i<n;i++){
int h,m,s;
scanf("%d:%d:%d",&h,&m,&s);
d[h*3600+m*60+s]++;
scanf("%d:%d:%d",&h,&m,&s);
d[h*3600+m*60+s+1]—;
}
int t=60*3600+60*60+60,mx=0;
for(int i=1;i<t;i++){
d[i]+=d[i–1];
mx=max(mx,d[i]);
}
cout<<mx;
return 0;
}
L2-4 被n整除的n位数
DFS 本题正解为DFS,按位构造数字并同步判断整除性,当位数达到 n 时校验是否在数值范围内即可。 当时我不会写DFS,因此采用了暴力枚举的写法:编写check函数后遍历区间内所有数字,最终拿到 14 分。 对于难度偏高的 L2 题目,暴力拿部分分是考场性价比很高的策略 check函数:
bool ck(int x){
string s,tmp="";
s=to_string(x);
int len=s.size();
s=" "+s;
for(int i=1;i<=len;i++){
tmp+=s[i];
if(stoi(tmp)%i!=0)return 0;
}
return 1;
}
正解
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+9;
int a,b,t,x,n;
string s;
bool fd=0;
void dfs(int u,int cnt){
if(u==n){
if(cnt>=a&&cnt<=b){
fd=1;
cout<<cnt<<'\\n';
}
return ;
}
for(int i=0;i<=9;i++){
int tmp=cnt*10+i;
if(tmp%(u+1))continue;
dfs(u+1,tmp);
}
}
signed main(){
cin>>n>>a>>b;
for(int i=1;i<=9;i++)
dfs(1,i);
if(!fd)cout<<"No Solution";
return 0;
}
备赛经验与刷题建议
结合两次参赛的经历,我整理了 4 条备赛建议,尤其适合目标冲击 L2 高分、冲击国奖的选手参考。
网硕互联帮助中心






评论前必须登录!
注册