十五届蓝桥杯总结

# **15届蓝桥杯总结**
对于本次蓝桥杯比赛,我认为我发挥得不是很好。
原因有三:
    - 基础算法没有掌握好
    - 没做好时间分配
    - 一些知识点掌握得不牢
因此我打算对我之前学过的基础算法进行总结巩固练习。

------------
### 一些技巧上的总结
#### 数字与字符串之间的转换
使用c11版本的devc++,可以使用自带的库函数实现字符串转整数( stoi() ),代码如下:
```cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
    string s="1123456";
    int a=stoi(s);
    cout<<a<<endl;
    return 0;
}
```
![](https://www.ylcode.cloud/wp-content/uploads/2024/04/联想截图_20240414152737-300x85.png)

当然你还可以使用sscanf映射,具体语法如下:
使用sscanf将字符串转成整数,该字符串需要是char数组
```cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
    int a=0;
    char s[7]="123456";
    sscanf(s,"%d",&a);//将s从左到右以整数输入到a,注意需要 取址(&)符
    cout<<"a="<<a<<endl;
    return 0;
}
```

![](https://www.ylcode.cloud/wp-content/uploads/2024/04/联想截图_20240414154047-300x87.png)

当然你还可以使用**stringstream**来实现,需要引用头文件:    "sstream"
具体代码如下:
```cpp
#include<iostream>
#include<sstream>
using namespace std;
int main(){
    string s="233333";
    stringstream ss(s);
    int a;
    ss>>a;
    cout<<a<<endl;
    return 0;
}
```

![](https://www.ylcode.cloud/wp-content/uploads/2024/04/联想截图_20240414154532-300x85.png)

####      **int转string**
前面我们提到sscanf可以将字符串转换成整数,那么sprintf()显然就可以将整数转换成字符串啦!之前sscanf是不是将左边的输入给右边,那么sprintf就是将右边的输入到左边咯,不同的是sprintf不需要&符(~~你见过谁家打印函数需要取址符的~~),示例代码如下:
```cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
    int a=2335468;
    char tmp[10];
    sprintf(tmp,"%d",a);
    string s=tmp;
    cout<<s<<endl;
    return 0;
}

```

![](https://www.ylcode.cloud/wp-content/uploads/2024/04/联想截图_20240414155938-300x77.png)

我们还可以使用itoa函数实现,调用include <stdlib.h>
具体语法:* char *  itoa ( int value, char * str, int base ); 解释:value是我们要转化的数,str是用来接收的,后面的base是转化后的进制数 ,示例代码如下:
```cpp
#include<iostream>
#include<stdlib.h>
using namespace std;
int main(){
    int value=123456;
    char str[10];
    itoa(value,str,10);
    cout<<"str="<<str<<endl;
    return 0;
}
```


![](https://www.ylcode.cloud/wp-content/uploads/2024/04/联想截图_20240414161516-300x77.png)


**个人更加喜欢sscanf和sprintf,因为这两个函数适用性更广,你可以将%d改成%f或者其他的,这样你就可以实现浮点数与字符串的转换.**

当然还有to_string方法,学过Java的同学都知道to_string方法可以将各种数据类型转换成字符串,示例代码如下:
```cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
    int a=123456;
    double d=123.456;
    long long l=1235465489;
    string s1=to_string(a);
    string s2=to_string(d);
    string s3=to_string(l);
    cout<<"s1="<<s1<<endl;
    cout<<"s2="<<s2<<endl;
    cout<<"s3="<<s3<<endl;
    return 0;
}
```
#### 四舍五入
有时候题目会要求我们输出四舍五入的结果,因此我们需要知道这方面的知识。
一般题目要求无非分为两种:

**1.四舍五入只保留整数**
    1)只需要输出就可以,那么这时候我们就可以使用printf函数实现这一功能了,示例代码:
```cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
    //只要求输出
    double d=123.45;
    printf("%.0lf",d);
    return 0;
}
```


![](https://www.ylcode.cloud/wp-content/uploads/2024/04/联想截图_20240414165604-300x65.png)

2)保留结果
    直接调用cmath中的round函数
```cpp
#include<iostream>
#include<cmath>
using namespace std;
int main(){
    //要求保留结果
    double a=123.456;
    double b=3456.2464161;
    double c=25875.22235;
    cout<<"round(a) = "<<round(a)<<endl;
    cout<<"round(b) = "<<round(b)<<endl;
    cout<<"round(c) = "<<round(c)<<endl;
    return 0;
}
```

![](https://www.ylcode.cloud/wp-content/uploads/2024/04/联想截图_20240414170016-300x115.png)

**2. 保留小数点后k位**
    1)只要求输出
```cpp
#include<iostream>
#include<cmath>
using namespace std;
int main(){
    //保留小数点后k位
    double d=123.456;//小数点后有三位,我们保留两位,那么之后的就会往前补齐,但是如果在第2位后的第1位小于5,那么就算补齐还是不变的
    printf("%.2lf",d);//保留小数点后2位
    return 0;
}
```

![](https://www.ylcode.cloud/wp-content/uploads/2024/04/联想截图_20240414170506-300x50.png)

2)要求保留结果

------------


## 基础算法
####  模拟

#### 高精度
高精度一般是用于实现超出long long或者double表示范围的加法、减法、乘法和除法。基本原理就是:使用字符串模拟数字的计算,利用类似于数学里的竖式表示,一位一位进行计算的。

##### 高精度加法
主要的核心操作就是使用数组去模拟加法的进位,以及去除前导0
代码如下:
```cpp
#include<bits/stdc++.h>
using namespace std;
int a[505],b[505],c[555]; //a b数组为加数 和 被加数  ,c数组存进位和结果
int main(){
    string s1,s2;
    cin>>s1>>s2;
    int l1=s1.size();
    int l2=s2.size();
    for(int i=0;i<l1;i++){
        a[l1-i-1]=s1[i]-'0';//将操作数倒置 比如我们输入123 我们想从低位开始操作就必须倒置成321
    }
    for(int i=0;i<l2;i++){
        b[l2-i-1]=s2[i]-'0';
    }
    int l3= max(l1,l2) + 1;//取l1和l2中最大的然后加1 因为加法有进位 比如12+88=100 加数和被加数都是两位 但是结果为3位
    //运算
    for(int i=0;i<l3;i++){
        c[i]+=a[i]+b[i];//等同于 c[i] = a[i] + b[i] + c[i] ;
        if(c[i] >= 10 ){//如果 加完之后>=10,就需要进位
            c[i+1] += c[i]/10;//i的下一位 + 第i位/10
            c[i]=c[i]%10;//留下进位之后剩余的数
        }
    
    }
    while(c[l3-1] ==0 && l3>1 ) l3--;//去掉前导0 并且保证留最少1位 因为如果是 0 + 0 = 0 ,他的结果只有1个数(0) ,所以不能去掉
    for(int i=l3-1;i>=0;i--) cout<<c[i];//打印结果
    return 0;
}

```
大家可以应用一下,这是一道洛谷上的高精度加法模版题:[高精度加法模版题](https://www.luogu.com.cn/problem/P1601 "高精度加法模版题")

##### 高精度减法
高精度加法需要进位,那么减法当然需要借位啦,同样滴,减法也需要注意去除前导0 , 代码如下:
```cpp
#include<bits/stdc++.h>
using namespace std;
int a[10087],b[10087],c[10087];
bool cmp(string s1,string s2){//比较减数与被减数的大小 只需要需要字符串的长度即可 如果s1的长度大于s2 那么
    if(s1.length() < s2.length() ) return true;//如果s1的长度小于s2 那么需要交换 返回true  
    if(s1.length() == s2.length() && s1<s2 ) return true;//如果s1与s2长度相等但是 s1>s2 也需要交换 返回true
    return false;//上述均不满足 就返回false
}
int main(){
    string s1,s2;
    int flag=0;//flag变量用于表示是否需要输出负号
    cin>>s1>>s2;

    if(cmp(s1,s2)){
        flag=1;//如果需要交换 那么说明s1小于s2 相当于 1 - 2 所以结果是负数 需要输出负号
        swap(s1,s2);//交换;两个数 原因  1 - 5 运算 是不是相当于 5 - 1 然后结果加一个负号
    }
    
    int l1=s1.size();
    int l2=s2.size();
    
    for(int i=0;i<l1;i++) a[l1-i-1]=s1[i]-'0';//数组倒置 与高精度加法一样
    for(int i=0;i<l2;i++) b[l2-i-1]=s2[i]-'0';
    int l3=max(l1,l2);//减法不需要 长度+1  
    for(int i=0;i<l3;i++){
        if(a[i] < b[i]){//如果当前数 小于 被减数  说明需要借位 那么 i+1 位 减 1 i位加10
            a[i+1]--;
            a[i] += 10;
        }
        c[i]=a[i]-b[i];//执行减法
    }
    while(c[l3-1] ==0 && l3>1 ) l3--;//与高精度加法一样  去除前导0
    if(flag) cout<<"-";//如果结果为负数 输出负号
    for(int i=l3-1;i>=0;i--) cout<<c[i];//输出结果
    return 0;
}

```
同样,来练一下手吧!题目链接:[高精度减法模版题](https://www.luogu.com.cn/problem/P2142 "高精度减法模版题")


ok,接下来就轮到高精度乘法和高精度除法啦!!!
##### 高精度乘法
高精度乘法分为高精度乘以高精度、高精度乘以低精度

##### 高精度乘以低精度
高精度乘以低精度我们只需要对一个数进行字符串的模拟操作即可(对大数进行操作),其核心的操作是逐位相乘,处理进位,对于乘法和除法除了考虑去除前导0的操作之外,还需要判断进位是否会导致长度l增加,代码如下:
```cpp
#include<bits/stdc++.h>
using namespace std;
int a[505],b[505],c[505];
int main(){
    string s1;
    int d;
    cin>>s1>>d;
    int l=s1.size();
    
    for(int i=0;i<l;i++) a[l-i-1]=s1[i]-'0';
    
    for(int i=0;i<l;i++){
        c[i] += a[i]*d;//等同于 c[i]=c[i] + a[i]*d
        if(c[i] >= 10){//处理进位
            c[i+1] += c[i]/10;
            c[i] = c[i] % 10;
         }
    }
    if(c[l] > 0) l++;//判断是否需要进位到c[l]位置
    while(c[l-1] == 0 && l > 1) l--;
    for(int i=l-1;i >= 0;i--) cout<<c[i];
    return 0;
}

```
##### 高精度乘以高精度
高精度乘以高精度的话,相比于高乘以低,我们这里需要两个for循环嵌套来模拟乘法每一位对应相乘和移位,代码如下:
```cpp
#include<bits/stdc++.h>
using namespace std;
int a[200],b[200],c[500];
int main()
{
    string s1,s2;
    cin>>s1>>s2;
    int l1=s1.size();
    for(int i=0;i<l1;i++) a[l1-i-1]=s1[i]-'0';
    int l2=s2.size();
    for(int i=0;i<l2;i++) b[l2-i-1]=s2[i]-'0';
    
    for(int i=0;i<l1;i++){
        for(int j=0;j<l2;j++){
            int k=i+j;
            c[k] += a[i]*b[j];
            if(c[k]>=10){
                c[k+1] += c[k]/10;
                c[k]=c[k]%10;
            }
        }
    }
    int l=l1+l2+1;
    if(c[l] > 0) l++;
    while(c[l-1]==0&&l>1) l--;
    for(int i=l-1;i>=0;i--) cout<<c[i];    
    return 0;
}

```
老规矩,模版题传送门:[高精度乘法(高精度乘高精度)模版题](https://www.luogu.com.cn/problem/P1303 "高精度乘法(高精度乘高精度)模版题")


------------

#### 前缀和与差分
前缀和一般应用在题目要求你求:
1. 子数组和(比如:最大子数组和或最小子数组和)
2. 区间和
3.数组元素的更新

前缀和分为一维前缀和和二维前缀和

一维前缀和:sum[i] = a[i] + sum[i];
就是 当前sum数组的第 i 位 等于 数组a的第i位元素 + sum数组的第 i-1 位。
示例代码:
```cpp
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],sum[N];//a数组存原本的元素 , sum数组构造前缀和
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) sum[i] = a[i] + sum[i-1] ;// 核心
    int q;
    cin>>q;//q次询问
    while(q--){
        int l,r;
        cin>>l>>r;//输入区间的左右范围
        cout<<sum[r]-sum[l-1]<<endl;
    }
    return 0;
}
```
模版题:[一维前缀和模版题](https://www.luogu.com.cn/problem/B3612 "一维前缀和模版题")

------------


#### 构造

------------

#### 二分答案法

------------


#### 排序

------------

####    分治

------------

#### 贪心


------------

  • 24
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值