洛谷学习总集1
洛谷代码学习总集 1
目录索引
因为在学习STL,所以有些代码使用 vector / set / unordered_map 实现了,但是除了声明不一样,使用和传统数组类似。
B2002 Hello瓦露多 || P3954 给公式算总成绩
考核你的 输入输出流/基本表达式运算 掌握的能力 不多说洼路多代码
#include<iostream> int main(){ std::cout<<"Hello,World!"; }
总成绩代码
#include<iostream> using std::cin,std::cout; int main(){ int total{0}; int input; cin>>input; total+=(0.20*input); cin>>input; total+=(0.30*input); cin>>input; total+=(0.50*input); cout<<total; }
P5707 给定路程速度 算出门的24小时制时间
思路:把所有时间换算成分钟单位的绝对时间(例如 8:25 就等于 8×60 + 25 分钟),算上必然的10分钟和路程时间去作差,如果是负数就在前一天,然后再除60和求模得到(小时:分钟)
坑:
- 注意“退位”,如果出发时间在前一天,分钟得到负值需要让小时-1。
- 注意手动取整
- 注意补0
点击查看代码
#include<iostream> #include<cmath> #define ARRIVEHOUR (8*60) int main(){ int s; int v; std::cin>>s>>v; //float t{1.000}; int Mins{ARRIVEHOUR-10}; int Hours; int t; if(s%v==0) t=s/v; else t=s/v+1; Mins -= t; switch(Mins < 0){ case false: Hours = (Mins/60); Mins = Mins%60; break; default: Hours = 23 + (Mins/60); Mins = 60 + Mins%60;break; } if(Hours < 10) std::cout<<0; std::cout<<Hours<<':'; if(Mins < 10) std::cout<<0; std::cout<<Mins; return 0; }
P5717 给定三角形三边判断类型
逻辑优化思路:基本思路很简单,判断输入三边的关系,先判断是不是三角形,再判断锐角钝角直角,再判断等腰以及等边。
坑点:输入的三边并不确定大小顺序,如果只判断一次,可能会因为“巧合”错下结论
解决思路:
- 暴力求解:直接对三边都进行判断。可以直接扩写条件表达式,也可以来回“交换”三边的判断顺序
- 排序求解:先对三边进行排序,确认长短边关系的同时也可以同时得到是否等腰/等边
点击查看代码
暴力求解(循环判断): 通过对下标求模完成从边0到边2的循环判断
#include<iostream> using std::cin,std::cout; int main(){ int edge[3]; cin>>edge[0]>>edge[1]>>edge[2]; int a,b,c; int count{0}; for (int i = 0; i < 3; i++) { a = edge[i%3]; b = edge[(i+1)%3]; c = edge[(i+2)%3]; if(a+b>c){ count++; } } if (count<3) {cout<<"Not triangle\n";return 0;} for (int i = 0; i < 3; i++) { a = edge[i%3]; b = edge[(i+1)%3]; c = edge[(i+2)%3]; a = a*a;b = b*b;c=c*c; if(a+b==c){ cout<<"Right triangle\n"; count = 0; break; } else if(a+b>c){ count-=114; } else if(a+b<c) count=114514; //cout<<count<<"\n"; } if(count > 0){cout<<"Obtuse triangle\n";} else if(count < 0){cout<<"Acute triangle\n";} if(a==b || b==c || a==c){ cout<<"Isosceles triangle\n"; if(a==b && b==c){ cout<<"Equilateral triangle\n"; } } return 0; }
我也比较想写排序写法,等有时间的
P1055 校验码对比和校正
思路:数据处理方式存在差异
- 把编码以字符串方式读入,然后对各位数码字符转成整数并且求解,遇到'-'直接跳过
- 把编码方式以数字方式读入,然后求模得到各位数字,利用scanf格式控制可以避开输入‘-’(输入流需要:var <<'-'<< var )
操作区别:
两种不同数据处理方式在输出上有些不同
- 如果直接以std::string(c的话char* 同理)读入,那么我们算完校验码可以直接把最后一位重新赋值后再把那个std::string对象送出去
- 如果数字方式读入,构建字符串再输出有些过于麻烦,一个一个数字或者几个数字循环送到输出流同时特定位置插入‘-’效果会好一些。
坑点:没啥坑点,注意校验位如果是10,需要换成‘X’表示
点击查看代码
我是第一种思路 (inline显式定义了内联函数,编译器会像宏定义一样在编译时直接在对应位置展开函数体内容,而不是反复跳转)(纯编程习惯 没有什么影响)#include<iostream> using std::cin,std::cout; inline int convert(char c){ if(c == 'X') return 10; return (c-'0'); } inline int convert(int i){ if(i == 10) return 'X'; else return (i+'0'); } int main(){ std::string input; cin>>input; int sum{0}; int count{1}; for (int i = 0; i < 11; i++) { if(i==1 || i==5){ continue; } sum+=(convert(input[i])*count); //cout<<convert(input[i])<<"*"<<count<<'\n'; count++; } count = sum % 11; //cout<<count; if(input[12]!=convert(count)){ input[12] = convert(count); cout<<input; } else cout<<"Right"; }
P2615 生成奇数阶幻方
思路:(如果不知道幻方生成算法)如果把给定示例放到execl表格中手动构建一下,发现其实不过是在做一件事:尝试把数字放在当前位置右上角的格子处,但是:
- 如果格子被占用,放在当前格子下方
- 如果右上角超出边界,则从另一侧边界进入放下数字。(有点像v社的传送门游戏,上下两条边界和左右两条边界对应建立两对传送门,数字从右边界出去会落在左边界右侧,从上边界出去会落在下边界上侧)
- 初始数字为1, 放在首行中间
坑点:
- 题目描述墨墨唧唧,故意要把人绕进去
- 如何实现 “传送门机制”
- 动态建立方阵 / 把所需空间建立在静态的39阶方阵中
- 判断位置是否被占用(有些编译器在开拓栈空间的时候会清零或者初始化为固定的数,此处我们假定初始化时数组内为随机的数)
(c语言中 c99以上支持通过 array[N]{0}或者string[N]{"\0"}或者something[N]{}来初始化为零值,cpp11同理)
但是只能初始化为零值
点击查看代码
我本来想将把int写个别名叫position
然后寻思着通过position类型 运算符重载求模运算实现传送门机制(求模可以实现 单向传送门,例如假定n为坐标,大小为3:n=3时,对3求模就变成0)
(什么异想天开 一拍脑袋 脑洞大开)
但是不可以对int类型的运算符进行运算符重载啦~
注意:
如果想要通过把n赋给const int实现控制“数组大小”,这是非常“不推荐的做法”(而且仅支持c99以上,因为c99之前要求变量声明必须统一在函数开头),你会发现开启O2优化后程序执行结果会出现问题。
#include<iostream> using std::cin,std::cout; inline int abs(int i){ return ((i>0)*i+(i<0)*(-i)); } using position = int; inline position limitToSize(int i,int size){ if(i>0) return i%size; else if(i<0) return (i%size)+size; else return 0; } int main(){ int n; cin>>n; const int size{n}; int magic_square[39][39]; bool tag[39][39]{false}; //我使用布尔数组,可以稳定初始化为false值,也可以通过变成位来优化大小 position i = 0; position j = size/2; //坐标,但是其实如果用指针会更像c hhhhhhh for (int num = 1; num <= size*size; num++) { if (!tag[i][j]) { magic_square[i][j] = num; tag[i][j]=true; i = limitToSize(i-1,size); j = limitToSize(j+1,size); //移动到右上角 } else{ j = limitToSize(j-1,size); i = limitToSize(i+2,size); //退回原位置的同时下移一格 //我们的函数会把给定值双向的限制在size范围内, //所以对一个数进行对称的操作相当于无操作 magic_square[i][j] = num; tag[i][j] = true; i = limitToSize(i-1,size); j = limitToSize(j+1,size); } } for (int a = 0; a < size; a++) { for (int b = 0; b < size; b++) { cout<<magic_square[a][b]<<' '; } cout<<std::endl;} return 0; }
P1914 凯撒密码实现
思路:肥肠滴简单阿,我们的字母ascii码与字母本身在字母表的位置存在着唯一映射关系(人话:ascii码稳定等于字母序号+某个定值(也就是’a‘的ascii值))
直接对字符串里面每一个元素都还原成字母表序号,对26求模,再还原为字符就好了 oriPasswd[i]=((oriPasswd[i]-'a'+unit)%26)+'a';
坑点:题目描述无用信息太多
- 可能对ascii码和字符的理解要求比较高?
- 没了,题本身没什么陷阱或者高难度
点击查看代码
#include<iostream> using std::cin,std::cout; int main(){ int unit{0}; std::string oriPasswd; cin>>unit; cin>>oriPasswd; for (int i = 0; i < oriPasswd.length(); i++) { oriPasswd[i]=((oriPasswd[i]-'a'+unit)%26)+'a'; } cout<<oriPasswd; }
P1308 find + word count
思路:先匹配首字母,再查找前后是否有空格(同时可以判断单词长度是否一致)(这意味着他是单独的词),然后再挨个字母去判断是否为同一个词
(例如: abc和bbc显然不是同一个词,abc和abcc显然不是同一个词,abc和acc显然不是同一个词,先首先判断容易判断的要素)
坑点:
- 不区分大小写,意味着每一个字母都要同时确认两个字符
- 首单词和尾单词分别在前和后都没有空格,要针对特例单独分析,所以在这些位置就可以不检测空格了(取这些位置会越界 属于未定义行为!仅仅比较问题不大,但是切记不要去赋值!)
- scanf()和输入流会将空格视作分隔符,输入句子请使用getline(),或者循环输入单词直到读取换行符
- 计数器。必须将所有字符都成功匹配才能进行加一。
点击查看代码
#include<iostream> using std::cin,std::cout; inline char con(char c){ if(c>='A'&&c<='Z') return c+('a'-'A'); else if (c>='a'&&c<='z') return c-('a'-'A'); else return '\0'; } int main(){ std::string word; std::string sentence; int pos{-1}; int count{0}; cin>>word; cin.ignore(); getline(cin,sentence); for(int i = 0; i <= sentence.length();i++){ bool terminate{false}; bool has_theSame_First_Char{(word[0]==sentence[i] || con(word[0])==sentence[i])}; bool is_aSingle_Word{(i==0||sentence[i-1]==' ')&&(i+word.length()==sentence.length()||sentence[i+word.length()]==' ')}; if(has_theSame_First_Char&&is_aSingle_Word){ for (int j = word.length()-1; j > 0; j--) { if(word[j]!=sentence[i+j]&&con(word[j])!=sentence[i+j]){ terminate = true; //如果匹配失败,中途中断,读取这个标志,计数器不会加一 break; } } if (!terminate) { count++; if(pos==-1) pos = i; i+=word.length(); //由于要求必须检测到的是完整单词,所以在检测成功后我们可以直接跳到下个单词 //有更高效的办法,外层循环直接以单词为索引,而不是以字母为索引,这需要检测分隔符数量,或者循环读入并且分别存在数组元素中。 //我这里相当于用传统的子串查找办法,而且是暴力版本。很低效 } } } if(pos!=-1) cout<<count<<' '<<pos<<'\n'; else cout<<pos<<'\n'; return 0; } //To be or not to be is a question -- 沙比
P5740 最值判断
思路:每个学生建立一个结构体,使用结构体数组,方便求完最值后回溯到对应元素
坑点:没啥坑点,最值判断的时候记录好最值对应的下标,输入的时候格式化做好,就行。
点击查看代码
#include<iostream> #include<vector> using std::cin,std::cout; typedef struct{ std::string name; int zhcn; int math; int eng ; }studentInfo; int main(){ int max[2]{0,0}; int n; cin>>n; std::vector<studentInfo> input; for (int i = 0; i < n; i++){ studentInfo t; cin>>t.name; cin>>t.zhcn; cin>>t.math; cin>>t.eng ; //或者也可以直接cin>>t.name>>t.zhcn>>t.math>>t.eng; int sum = t.zhcn + t.math + t.eng; if(max[0]<sum){ max[0] = sum; max[1] = i ; } input.push_back(t); } cout<<input[max[1]].name<<' '<<input[max[1]].zhcn<<' '<<input[max[1]].math<<' '<<input[max[1]].eng<<'\n'; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】