天梯赛练习集 时间规划 限时复盘 中档题详解(L1-6~L2-4)

今天小模拟了一下天梯赛的考试,这些题不是真题,只是模拟题,不过在网上都搜得到。

比如团体程序设计天梯赛-练习集L1-043 阅览室 (20 分)_牛客网等等。

如果是这样可以宣告打铁了。

关于时间

那么我先说说对于时间怎么分配是合适的。

笔者的水平理论极限值是前12题拿满+剩下3题的暴力。

而天梯赛限时三个小时,要干掉15个题(实际上写完14个都算发挥超常了),对于时间的把控程度不亚于考一张理综。

那么我们练的就要是熟练度,还有debug的能力。我觉得真正对考试起到决定性作用的是 L1 6-8的速度和 L2 四个题的前后顺序,这些题处理的如何直接决定着你能不能按照你的水平完美发挥出来,而不留空题。

L1

这里宛如数学的前8个选择(老高考12单选模式),基本上是平推的,但是也大有可能在这里出问题。我做完L1-4用时15min,做完L1-8用时1h25min。可以说接近崩盘了。

L1-6 检查密码 考点:字符串处理

好,这是字符串处理+ifelse语句。

我犯下的错误是:把<写成<=,导致处理到字符串结尾,也就是'\0'处。

cpp 复制代码
#include<iostream>
#include<iomanip>
#include<cmath>
#define i64 long long
using namespace std;
string s;
i64 n=0;
bool num=0,word=0,oth=0;
int main(){
	cin>>n;
	cin.ignore();
	while(n--){
		num=0,word=0,oth=0;
		getline(cin,s);
		//cout<<s<<' '<<s.length()<<endl;
		if(s.length()<6){
			cout<<"Your password is tai duan le.";
		}
		else{
			for(i64 i=0;i<s.length();i++){
				if(s[i]<='9'&&s[i]>='0'){
					num=1;
				}
				if((s[i]<='z'&&s[i]>='a')||(s[i]<='Z'&&s[i]>='A')){
					word=1;
				}
				if(!(s[i]<='z'&&s[i]>='a') && !(s[i]<='Z'&&s[i]>='A') && !(s[i]<='9'&&s[i]>='0') && !(s[i]=='.') ){
					//cout<<"乱"<<s[i]<<i<<endl;
					oth=1;
				}
			}
			//cout<<num<<' '<<word<<' '<<oth<<endl;
			if(oth==1) cout<<"Your password is tai luan le.";
			else{
				if(word==1&&num==0) cout<<"Your password needs shu zi.";
				else if(word==0&&num==1) cout<<"Your password needs zi mu.";
				else cout<<"Your password is wan mei.";
			}
		}
		if(n!=0) cout<<endl;
	}
	return 0;
}

L1-7 谷歌的招聘 考点:字符串处理、素数判断

这一题简而言之就是从字符串截取一个特定长度看是否为质数。

好,字符串截取问题,犯下了如下错误:

1.灾难性地忘记了s.substr(),纯手写函数

2.最后一个遍历的位置=len-k,而不是len-k-1。比如k=5,len-k的位置往后就可以截取到

s[len-5]s[len-4]s[len-3]s[len-2]s[len-1]。而不会到达len本身这个'\0'处,也不会漏一个字符。

3.不知道怎么输出前导0,好在最后想明白了。

最后19/20.

cpp 复制代码
#include<iostream>
#include<iomanip>
#include<cmath>
#define i64 long long
using namespace std;
string s;
bool flag=0;
i64 n,k,len;
i64 fun(i64 pos);
bool isprime(i64 num);
void mycout(i64 num);
int main(){
	cin>>len>>k;
	cin>>s;
	for(i64 i=0;i<=len-k;i++){
		if(isprime(fun(i))){
			mycout(fun(i));
			flag=1;
			break;
		}
	}
	if(!flag) cout<<404<<endl;
	return 0;
}
i64 fun(i64 pos){
	i64 num=0;
	for(i64 i=pos;i<pos+k;i++){
		num=num*10+(s[i]-'0');
	}
	return num;
}
bool isprime(i64 num){
	if(num==1) return 0;
	for(i64 i=2;i<=sqrt(num);i++){
		if(num%i==0)
			return 0;
	}
	return 1;
}
void mycout(i64 num){
	for(i64 i=1;i<=k;i++){
		cout<<num/(i64)pow(10,k-i)%10;
	}
	return ;
}
/*
6 4
200236
*/

L1-8 阅览室 考点:字符串处理、标志位灵活运用

输入样例:

3

1 S 08:10

2 S 08:35

1 E 10:00

2 E 13:16

0 S 17:00

0 S 17:00

3 E 08:10

1 S 08:20

2 S 09:00

1 E 09:20

0 E 17:00

输出样例:

2 196

0 0

1 60

这题本身就是传说中的恶心人的题了,我也确确实实在这上面花了不配它的时间。

但是天梯赛L1关必须打满80分,这一题就20分,所以不得不写。可惜,一写就是好久。

现在这题又要自己去写字符串处理函数。

读取出来的数还要传导出来到main函数本身这里。

然后就是时间判定逻辑,你必须有两个状态标志,第一个是记录时间,第二个是记录它之前的状态是否完善,不然可能读错数据。

最后需要四舍五入,用setprecision函数。

但是还是14/20。

cpp 复制代码
#include<iostream>
#include<iomanip>
#include<cmath>
#define i64 long long
using namespace std;
string s;
i64 n,num,oop,tms;
i64 a[1005],cnt=0,ans=0;
bool jie[1005];
void myread();
void init();
int main(){
	cin>>n;
	cin.ignore();
	while(n){
		getline(cin,s);
		myread();
		if(num==0){
			n--;
			double res=0;
			if(cnt>0){
				res=ans*1.0/cnt;
			}
			cout<<cnt<<' '<<fixed<<setprecision(0)<<res<<endl;
			cnt=0;
			ans=0;
			init();
			continue;
		}
		
		if(oop==1) {
			if(jie[num]==0){
				a[num]=tms;
				//cout<<ans<<' '<<num<<' '<<op<<' '<<tms<<endl;
				jie[num]=1;
			}
		}
		else if(oop==0){
			if(jie[num]==1){
				++cnt;
				ans+=tms-a[num];
				//cout<<ans<<' '<<num<<' '<<op<<' '<<tms<<endl;
				a[num]=0;
			}
		}	
	}
	return 0;
}
void myread(){
	i64 nnum=0,pos=0;
	for(i64 i=0;s[i]!=' ';i++){
		nnum=nnum*10+s[i]-'0';
		pos=i;
	}
	bool nnop;
	if(s[pos+2]=='S') nnop=1;
	else if(s[pos+2]=='E') nnop=0;
	
	i64 hh=0,mm=0,ntms=0;
	hh=(s[pos+4]-'0')*10+(s[pos+5]-'0');
	mm=(s[pos+7]-'0')*10+(s[pos+8]-'0');
	ntms=hh*60+mm;
	
	//cout<<nnum<<' '<<nop<<' '<<ntms<<endl;
	num=nnum;
	oop=nnop;
	tms=ntms;
	return ;
}
void init(){
	for(i64 i=1;i<=1000;i++){
		a[i]=0;
		jie[i]=0;
	}
	return ;
}

L2

做下来的感觉就是,L2的处理顺序完全决定着下限的高低。事实上目前见过的L2的所有题都是能暴力弄出来的,只是用时和得分平衡的问题。

L2-1 出栈序列的合法性 考点:栈、队列

它真的只是个栈模拟。。。

先把出栈数据压进一个队列q,然后把从1到n的整个入栈顺序给模拟出来,用stk[]和top记录。

如果本处是队首,那么该位置出栈、数据出队,这就是所谓的模拟出栈过程。

如果发现队列和栈没出干净,那就是不合法序列。

如果top超过限制m,就是栈太大,不合法。

花了25分钟。

cpp 复制代码
#include<iostream>
#include<iomanip>
#include<cmath>
#include<queue>
#define i64 long long
using namespace std;
i64 m,n,k,nixu=0; 
i64 a;
queue<i64> q;
int main(){
	cin>>m>>n>>k;
	while(k--){
		i64 flag=1;
		i64 stk[1005],top=0;
		for(i64 i=1;i<=n;i++){
			cin>>a;
			q.push(a);
		}
		for(i64 i=1;i<=n;i++){
			stk[++top]=i;
			if(top>m){
				flag=0;
				//cout<<"NO"<<endl;
			}
			while(!q.empty()&&stk[top]==q.front()){
				//cout<<stk[top]<<endl;
				stk[top--]=0;
				q.pop();
			} 
		}
		while(!q.empty()){
			flag=0;
			q.pop();
			//cout<<"NO"<<endl;
		}
		while(top){
			flag=0;
			stk[top--];
			//cout<<"NO"<<endl;
		}	
		if(flag) cout<<"YES";
		else cout<<"NO";
		if(k!=0) cout<<endl;
	}
	return 0;
}

L2-2 抢红包 考点:结构体排序

输入样例:

10

3 2 22 10 58 8 125

5 1 345 3 211 5 233 7 13 8 101

1 7 8800

2 1 1000 2 1000

2 4 250 10 320

6 5 11 9 22 8 33 7 44 10 55 4 2

1 3 8800

2 1 23 2 123

1 8 250

4 2 121 4 516 7 112 9 10

输出样例:

1 11.63

2 3.63

8 3.63

3 2.11

7 1.69

6 -1.67

9 -2.18

10 -3.26

5 -3.26

4 -12.32

注意元角分的转换,注意排序顺序是收入------收到红包个数------个人编号。

所以就是道简单结构体排序,理清楚题意,定义好结构体即可。

花了25分钟,感觉这类题练熟来得写进20分钟。

cpp 复制代码
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<queue>
#define i64 long long
using namespace std;
i64 n,k,ni,pi,a[10005],c[10005];
struct node{
	i64 num,mon,rec;
}b[10005];
bool cmp(struct node x,struct node y){
	if(x.mon==y.mon){
		if(x.rec==y.rec){
			return x.num<y.num;
		}
		return x.rec>y.rec;
	}	
	return x.mon>y.mon;
}
int main(){
	cin>>n;
	for(i64 i=1;i<=n;i++){
		cin>>k;
		for(i64 j=1;j<=k;j++){
			cin>>ni>>pi;
			c[ni]++;
			a[ni]+=pi;
			a[i]-=pi;
		}
	}
	for(i64 i=1;i<=n;i++){
		b[i].mon=a[i];
		b[i].num=i;
		b[i].rec=c[i];
	}
	sort(b+1,b+n+1,cmp);
	for(i64 i=1;i<=n;i++){
		cout<<b[i].num<<' '<<fixed<<setprecision(2)<<b[i].mon*1.0/100;
		cout<<endl;
	}
	return 0;
}

L2-3 二叉搜索树的2层节点统计 考点:数组模拟建树、二叉搜索树

如果学过数据结构,题意就很简单,模拟实现一个二叉排序树就行了。

不过一句"行了",恰恰是最不行的~~

数组怎么模拟树?首先定义好节点四元素:双亲、数值、左子、右子,写到后面发现要统计深度。

struct node{

i64 num,prt,lson,rson,depth;

}a[1005];

接着初始化。

然后就是实现二叉搜索树,也是我犯大错的地方。

号外:写到这里我突然想明白为什么会挂掉两个点了!

咳咳,二叉搜索树是不完美二叉树,它的树状肯定是千奇百怪,但是要能够精准定位到节点,那就来模拟一次:

搜索拐弯有两种情况:数值更小,或者节点是叶子。

向右搜索,直到拐弯;向左搜索,直到拐弯;再向右,再向左;循环往复。(我漏掉了外面的大层循环。)

给一个测试点,这个树是一条蜿蜒的河。

7

50 60 70 65 61 63 62

然后就是条件判断和统计,这些比较繁琐但不难。

喜提AC。

cpp 复制代码
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<queue>
#define i64 long long
using namespace std;
i64 n,x;
struct node{
	i64 num,prt,lson,rson,depth;
}a[1005];
void dfs(i64 x);
int main(){
	cin>>n;
	for(i64 i=1;i<=n;i++){
		cin>>x;
		a[i].num=x;
		a[i].prt=-1;
		a[i].lson=-1;
		a[i].rson=-1;
		a[i].depth=1;
	}
	for(i64 i=2;i<=n;i++){
		i64 nxt=i,lst=1;
		while(1) {
			//先向右 
			if(a[nxt].num>a[lst].num){
				if(a[lst].rson!=-1){
					lst=a[lst].rson;
				}else{
					break;
				}
			}else if(a[nxt].num<=a[lst].num){
				if(a[lst].lson!=-1){
					lst=a[lst].lson;
				}else{
					break;
				}
			}
			else break;
		}
		if(a[nxt].num<=a[lst].num){
			a[nxt].prt=lst;
			a[lst].lson=nxt;
			a[nxt].depth=a[lst].depth+1;
			//cout<<666<<endl;
		}else{
			a[nxt].prt=lst;
			a[lst].rson=nxt;
			a[nxt].depth=a[lst].depth+1;
			//cout<<777<<endl;
		}
		//cout<<a[nxt].num<<' '<<a[nxt].prt<<' '<<a[nxt].rson<<' '<<a[nxt].lson<<endl;
		//cout<<a[lst].num<<' '<<a[lst].prt<<' '<<a[lst].rson<<' '<<a[lst].lson<<endl;
	}
	//dfs(1);
	i64 mx=0,cnt=0;
	for(i64 i=1;i<=n;i++){
		mx=max(mx,a[i].depth);
	}
	for(i64 i=1;i<=n;i++){
		if(a[i].depth==mx-1||a[i].depth==mx)
			++cnt;
	}
	cout<<cnt<<endl;
	return 0;
}
void dfs(i64 x){
	cout<<a[x].num<<' '<<a[x].depth<<endl;
	if(a[x].lson!=-1) dfs(a[x].lson);
	if(a[x].rson!=-1) dfs(a[x].rson);
	return ;
}
/*
9
25 30 42 16 20 20 35 -5 28
7
50 55 60 57 56 58 59
*/

L2-4 秀恩爱分得快 考点:矩阵表示法

输入样例 1:

10 4

4 -1 2 -3 4

4 2 -3 -5 -6

3 2 4 -5

3 -6 0 2

-3 2

输出样例 1:

-3 2

2 -5

2 -6

输入样例 2:

4 4

4 -1 2 -3 0

2 0 -3

2 2 -3

2 -1 2

-3 2

输出样例 2:

-3 2

目前这么长一坨代码15/25,写到超过时间半小时。

题目读了就能懂,模拟干就完了。

cpp 复制代码
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<queue>
#define i64 long long
using namespace std;
i64 n,m,k,x[2005],a,b;
double s[2005][2005]={0};
double qin=0;
bool cmp(i64 x,i64 y);
int main(){
	cin>>n>>m;
	for(i64 i=1;i<=m;i++){
		cin>>k;
		qin=1.0/k;
		for(i64 j=1;j<=k;j++){
			cin>>x[j];
		}
		for(i64 j=1;j<=k-1;j++){
			for(i64 t=j+1;t<=k;t++){
				//cout<<x[j]<<' '<<x[t]<<' '<<qin<<endl;
				s[x[j]+1000][x[t]+1000]+=qin;
				s[x[t]+1000][x[j]+1000]+=qin;
			}
		}
	}
	cin>>a>>b;
	a+=1000;
	b+=1000;
	
	i64 c=min(a,b);
	i64 d=max(a,b);
	double mx=0;
	bool f1=0,f2=0;
	i64 stk1[1005],top1=0;
	i64 stk2[1005],top2=0;
	
	for(i64 i=1000;i<=2000;i++){
		if(s[c][i]!=0){
			mx=max(mx,s[c][i]);
		}
	}
	for(i64 i=1000;i<=2000;i++){
		if(s[c][i]==mx){
			stk1[++top1]=i;
			if(i==d) f1=1;
		}
	}
	
	mx=0;
	for(i64 i=0;i<=1000;i++){
		if(s[d][i]!=0){
			mx=max(mx,s[d][i]);
		}
	}
	for(i64 i=0;i<=1000;i++){
		if(s[d][i]==mx){
			stk2[++top2]=i;
			if(i==c) f2=1;
		}
	}
	sort(stk2+1,stk2+top2+1,cmp); 
		
	if(f1&&f2){
		cout<<a-1000<<' '<<b-1000<<endl; 
	}else{
		//c必定女 d必定男
		if(c==a){//a女 
			for(i64 i=1;i<=top1;i++){
				cout<<c-1000<<' '<<stk1[i]-1000<<endl;
			}
			for(i64 i=1;i<=top2;i++){
				cout<<d-1000<<' '<<stk2[i]-1000<<endl;
			}
		}else if(c==b){//a男 
			for(i64 i=1;i<=top2;i++){
				cout<<d-1000<<' '<<stk2[i]-1000<<endl;
			}
			for(i64 i=1;i<=top1;i++){
				cout<<c-1000<<' '<<stk1[i]-1000<<endl;
			}
		}
	}
	return 0;
}
bool cmp(i64 x,i64 y){
	return x>y;
}

番外 L3-3的思考

然后这次的3-3是解析几何算面积,我本来想先动手这个的,但是发现越做要考虑的情况就越多,所以放弃了。

联想到我上一次CSP就是求把第五题暴力出来,结果越想条件越复杂,写了两小时没暴力出来。看第三题,我最后考试30分钟都快模拟完了,真的很简单,我回去完善一下写了75分。真的是被自己蠢哭了。

所以,题目这么给你牌是真得信它的道理的,不会真有人觉得暴力骗分是件简单活?

相关推荐
黑眼圈子2 小时前
总结一下用Java做算法的常用类和方法
java·开发语言·算法
再卷也是菜2 小时前
第一章、线性代数(2)高斯消元法
线性代数·算法
NAGNIP2 小时前
一文搞懂CNN经典架构-EfficientNet!
算法·面试
如何原谅奋力过但无声2 小时前
【chap11-动态规划(上 - 基础题目&背包问题)】用Python3刷《代码随想录》
数据结构·python·算法·动态规划
小宇的天下3 小时前
Calibre LVS Circuit Comparison(2)
算法·lvs
迈巴赫车主3 小时前
求最大公约数-欧几里得算法(辗转相除法)
算法·最大公约数
lxl13074 小时前
C++算法(15)BFS_FloodFill
算法·宽度优先
小王C语言4 小时前
【基础IO】————简单设计一下libc库
前端·数据结构·算法
亦复何言??4 小时前
BeyondMimic 论文解析
人工智能·算法·机器人