洛谷学习总集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';
}



posted @   Brakeintime  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示