愉快(并不)地考完了,看到LDY大佬的题解,决定学习一个,也来写一份解题报告。当然,这会是一个比较简易的版本,可能有所缺漏,敬请谅解。
此处是LDY大佬题解的传送门:
https://zhuanlan.zhihu.com/p/60305621
走过路过给个赞~
A. 恢复单词
单点时限: 2.0 sec
内存限制: 512 MB
学霸在背单词的时候发现单词的大小写混乱,而且可能参杂了0-9的数字和 %,+,&,#这四种特殊符号。请编写程序让单词恢复正常。要求处理后单词的首字母大写,且其余字母均为小写。
注意:单词虽然大小写混乱,但是字母间的顺序均正确。
例如:%sa+01t2urdAY,经过处理后为:Saturday
输入格式
混乱的单词s1, s1的长度<=100。
输出格式
去掉数字和特殊字符后的单词,单词首字母大写,其余字母小写。
s1中的数字
s1中的其它字符
样例
input
%sa+01t2urdAY
output
Saturday 012 %+
input
book
output
Book
提示
若对应内容不存在,则不用输出任何信息。
第一题考的是字符串的基本操作,用STL的string类可以说是事半功倍,如果用字符数组实现,大概要注意一下结尾的 ‘ \0 ‘。注意单词的大小写判断。还有提示里“任何信息”包括空格。
#include<bits/stdc++.h>//万能头文件 using namespace std; int main(){ string s1,word,num,other; int l,i; bool firLetter(false);//判断是否是第一个字母 cin>>s1; l=s1.length();//获得s1的长度 for(i=0;i<l;i++){ if(s1[i]>=‘a‘&&s1[i]<=‘z‘||s1[i]>=‘A‘&&s1[i]<=‘Z‘){//如果是字母 if(!firLetter&&s1[i]>=‘a‘)//是首字母且为小写 s1[i]+=‘A‘-‘a‘; else if(firLetter&&s1[i]<‘a‘)//不说首字母且为大写 s1[i]+=‘a‘-‘A‘; word+=s1[i]; firLetter=true; //接下去的都不是第一个字母 } else if(s1[i]>=‘0‘&&s1[i]<=‘9‘)//是数字 num+=s1[i]; else other+=s1[i];//其他 } if(word.size()) cout<<word<<endl;//小心不要输出多余的空格 if(num.size()) cout<<num<<endl; if(other.size()) cout<<other<<endl; return 0; }
不再想一想吗?
B. 数位和
单点时限: 2.0 sec
内存限制: 512 MB
“数位和”是指:把一个整数的各位累加后的结果。
例如正整数 123456 的数位和是 1+2+3+4+5+6=21。
现在,请你帮忙计算一个整数 n 在 r 进制下的数位和,并用相应的进制输出结果。
输入格式
第 1 行:整数 T(1≤T≤10) 为问题数。
第 2 行:第一个问题的数据。包含两个正整数 n(1≤n≤2147483647) 和 r(2≤n≤16)。
第 3 ∽ T+1 行:后面问题的数据,格式与第一个问题相同。
输出格式
对于每个问题,输出一行问题的编号(0 开始编号,格式:case #0: 等),然后在一行中输出用 r 进制表示的十进制正整数 n转换成 r 进制后的数位和。
样例
input
2 123456 10 123456 2
output
case #0: 21 case #1: 110
提示
当r进制大于10时,用大写字母A-F表示大于10的数字。
例如:十进制数29转换为16进制为 1D,此时数位和为14,则正确的输出应为:E
两次进制转换即可,当然,好像有一次转换完成的办法。
#include<bits/stdc++.h> using namespace std; char apl[20]={‘0‘,‘1‘,‘2‘,‘3‘,‘4‘,‘5‘, ‘6‘,‘7‘,‘8‘,‘9‘,‘A‘,‘B‘,‘C‘,‘D‘,‘E‘,‘F‘};//进制转换用 void solve(){ int num,i(0),r,sum(0); char ans[100000]={}; cin>>num>>r; while(num){ sum+=num%r; num/=r; }//第一次进制转换 while(sum){ ans[i]=apl[sum%r]; i++; sum/=r; }//第二次进制转换 while(--i>=0)//逆序输出 cout<<ans[i]; cout<<endl; } int main(){ int t,i; cin>>t; for(i=0;i<t;i++) { printf("case #%d:\n",i); solve(); } return 0; }
不再想一想吗?
C. 谁是第一名
单点时限: 2.0 sec
内存限制: 512 MB
为了知道哪些学生最优秀,考虑他们的三项主要课程(C Programming Language, Mathematics , English)成绩和平均成绩(平均成绩四舍五入取整),分别用C,M,E,A表示。写一个程序,对学生的四项成绩进行排序并输出每项成绩的第一名。程序的输入为学生的学号和三门课程成绩,不包含平均成绩。
输入格式
第 1 行:一个整数 T (1≤T≤10) 为问题数。
对于每组测试数据:
第 1 行:整数 n (1≤n≤100) ,表示学生的数量。
第 2 行~第 n+1 行:每行分别是一个学生的成绩信息,包含学号(长度为 11),三门课程C, M, E的成绩G(G为整数且0<G≤100),各项之间都有一个空格。
输出格式
对于每个问题,输出一行问题的编号(0 开始编号,格式:case #0:等),然后分别输出A,C,M,E各项成绩中排名第一的学生的学号。当成绩并列第一时按按照学号的字典序顺序输出。
样例
input
2 5 10185101101 98 85 90 10185101102 98 95 88 10185101103 82 87 94 10185101104 91 91 91 10185101105 85 90 90 2 10185101103 82 87 94 10185101104 91 91 91
output
case #0: A: 10185101102 C: 10185101101 10185101102 M: 10185101102 E: 10185101103 case #1: A: 10185101104 C: 10185101104 M: 10185101104 E: 10185101103
提示
注意A(平均成绩)四舍五入取整数。
一道非常裸的排序题,一波STLsort解决之,注意A是取整数,如果用double反而不能通过。
#include<bits/stdc++.h> using namespace std; typedef long long ll; struct stu{//学生结构体 int c,m,e,a; ll id; }; bool cmpa(stu a,stu b){//比较函数 if(a.a!=b.a) return a.a>b.a; return a.id<b.id; } bool cmpc(stu a,stu b){ if(a.c!=b.c) return a.c>b.c; return a.id<b.id; } bool cmpm(stu a,stu b){ if(a.m!=b.m) return a.m>b.m; return a.id<b.id; } bool cmpe(stu a,stu b){ if(a.e!=b.e) return a.e>b.e; return a.id<b.id; } void solve(){ int n,i; stu stud[105]; cin>>n; for(i=0;i<n;i++){ scanf("%lld%d%d%d",&stud[i].id, &stud[i].c,&stud[i].m,&stud[i].e); stud[i].a=double(stud[i].c+stud[i].m+stud[i].e)/3+0.49; } sort(stud,stud+n,cmpa); cout<<"A:"<<endl<<stud[0].id<<endl; i=1; while(i<n&&stud[i].a==stud[0].a){//同时第一的输出,注意不要越界 cout<<stud[i].id<<endl; i++; } sort(stud,stud+n,cmpc); cout<<"C:"<<endl<<stud[0].id<<endl; i=1; while(i<n&&stud[i].c==stud[0].c){ cout<<stud[i].id<<endl; i++; } sort(stud,stud+n,cmpm); cout<<"M:"<<endl<<stud[0].id<<endl; i=1; while(i<n&&stud[i].m==stud[0].m){ cout<<stud[i].id<<endl; i++; } sort(stud,stud+n,cmpe); cout<<"E:"<<endl<<stud[0].id<<endl; i=1; while(i<n&&stud[i].e==stud[0].e){ cout<<stud[i].id<<endl; i++; } return ; } int main(){ int t,i; cin>>t; for(i=0;i<t;i++) { printf("case #%d:\n",i); solve(); } return 0; }
不再想一想吗?
D. 记忆碎片
单点时限: 2.0 sec
内存限制: 512 MB
在徒弟的记忆中,自入门以来,师父的身影似乎一直陪伴在自己身旁。
多年后,徒弟只剩下零碎的记忆片段,不过每段记忆片段却十分的清晰,并且能很明确的说出这段记忆发生在哪一段时间内。
徒弟很想知道自己和师父在一起一共有多少日子,请帮他解决上述问题。
输入格式
包含一个整数N
接下来的N行,每行包含两个不同的整数s, t,表示一段记忆碎片发生的起始时间s和结束时间t。
数据约束
对于60%的数据,N<=500,0<=s<=t<=1000
对于100%的数据,N<=5000, 0<=s<=t<=5000000
输出格式
一个整数,表示徒弟能回忆起的和师父在一起的日子总数
样例
input
3 100 200 150 300 470 471
output
203
提示
对于输入样例:
3
100 200
150 300
470 471
解释:
记忆中和师父在一起的日子为[100,300]和[470,471],一共203天。
这道题可以说是一道非常经典的贪心题了。
如果不说贪心,可以暴力模拟这个过程,开一个数组,对于每个区间内的数置一,最后把整个区间扫一遍。
显然这样只能过60%。那贪心是怎么操作的呢?我们首先可以看到,对暴力法,后期制约时间的主要因素是遍历区间的每个点,而相比之下更快速的办法是,对每个区间的end-start+1累加,但这样可能会重复计数。所以我们先对所有区间按区间头升序排列,然后开始维护一个当前区间,如果下一个区间的start比当前区间的end值更小,意味着下一个区间和当前区间是重合的,把下一个区间合并入当前区间,否则结算当前区间的长度,并把下一个区间作为新的当前区间。
注意最后一个区间需要特判。
#include<bits/stdc++.h> using namespace std; typedef long long ll; struct p{//区间头尾 int start,end; }; bool cmp(p a,p b){ if(a.start!=b.start) return a.start<b.start; return a.end<b.end; } int main(){ int n,i,start,end; ll ans(0); p part[5005]; cin>>n; for(i=0;i<n;i++) scanf("%d%d",&part[i].start,&part[i].end); sort(part,part+n,cmp); start=part[0].start; end=part[0].end; for(i=1;i<n;i++){ if(part[i].start>end){//不能合并 ans+=end-start+1;//注意+1 start=part[i].start; end=part[i].end; } else end=max(end,part[i].end);//合并 } ans+=end-start+1;//最后一个区间的特判 cout<<ans<<endl; return 0; }
不再想一想吗?
E. 徒弟的下山之路
单点时限: 2.0 sec
内存限制: 512 MB
终于到了出师的日子,徒弟需要从山顶的纯阳宫找一条花费最少时间的下山之路。
这座山用一个三角形来表示,从山顶依次向下有n层,第i层有i个可移动的位置,出口在最下层的左边。例如有一座5层的山:
1
3 2
4 5 6
9 1 7 8
1 1 4 5 6
此示例中出口为最下层最左边的1所在位置。山上每个数字代表徒弟路过这个位置需要花费的时间,徒弟下山总时间为路径上数字之和。
徒弟每次可以往左、右、左下、右下四个方向移动,例如徒弟位于第3层的数字5时可以向左走到4,向右走到6;也可以向左下走到1,向右下走到7;
又如徒弟位于第3层的数字6时,可以向左走到5,无法向右;也可以向左下走到7,向右下走到8;
输入格式
第一行一个整数n,表示山的高度
接下来n行,第i行有i个整数,表示徒弟经过这个位置需要的时间(路过每个位置花费的时间不超过10)。
数据约束
对于20%的数据,n=4
对于60%的数据,n<=10
对于100%的数据,n<=1000
输出格式
徒弟下山需要花费的最少时间
样例
input
5 1 3 2 4 5 6 9 1 7 8 1 1 4 5 6
output
11
提示
徒弟下山花费的时间为1+3+4+1+1+1=11
一眼看过去感觉就是数字三角形,再仔细一看发现可以向四个方向走......好吧,动态转移方程挺好写的,dp[i,j]=map[i,j]+max(dp[i,j-1],dp[i,j+1],dp[i+1,j],dp[i+1,j+1],但实现起来发现略麻烦。转换一下思路,可以用bfs解决,开一个队列,对队首可以到达的路径枚举,更新最短的路径,并把有更新的放入队中。写完发现这不就是Dijkstra吗?(捂脸
#include<bits/stdc++.h> using namespace std; typedef long long ll; int mapping[1005][1005],dp[1005][1005]; int directX[5]={0,0,1,1}; int directY[5]={-1,1,0,1};//方向数组 struct point{ int x,y,time; }x; int main(){ int n,i,j; cin>>n; for(i=1;i<=n;i++) for(j=1;j<=i;j++) scanf("%d",&mapping[i][j]); x.x=x.y=1; x.time=dp[1][1]=mapping[1][1]; queue<point> que; que.push(x); while(!que.empty()){//bfs x=que.front(); que.pop(); if(x.time>dp[x.x][x.y]) continue; for(i=0;i<4;i++){ x.x+=directX[i]; x.y+=directY[i]; x.time+=mapping[x.x][x.y];//新结点 if(mapping[x.x][x.y]&&(dp[x.x][x.y]>x.time||!dp[x.x][x.y])){//(没有越界&&(可以更新||没更新过)) que.push(x); dp[x.x][x.y]=x.time; } x.time-=mapping[x.x][x.y]; x.x-=directX[i]; x.y-=directY[i]; //还原为原结点 } } cout<<dp[n][1]<<endl; return 0; }
不再想一想吗?
原文地址:https://www.cnblogs.com/wengsy150943/p/10624942.html