蓝桥杯题库刷题
一.入门篇
二.基础篇
10.十进制转十六进制
(1)题目
(2)代码
方法一:暴力法
#include<iostream>
#include<stdlib.h>
using namespace std;
// 方法一:暴力法
int a;
int A[20];
char change (int m) {
switch(m) {
case 0:return '0'; break;
case 1:return '1'; break;
case 2:return '2'; break;
case 3:return '3'; break;
case 4:return '4'; break;
case 5:return '5'; break;
case 6:return '6'; break;
case 7:return '7'; break;
case 8:return '8'; break;
case 9:return '9'; break;
case 10:return 'A'; break;
case 11:return 'B'; break;
case 12:return 'C'; break;
case 13:return 'D'; break;
case 14:return 'E'; break;
case 15:return 'F'; break;
}
}
int main() {
scanf("%d",&a);
if(a < 0 || a > 2147483647) return -1;
int t = 0;
if(a == 0)
{
printf("0");
} // 0不能作被除数,所以如果输入0,则直接输出0
while(a) {
A[t++] = a % 16;
a /= 16;
}
for(int i = t - 1 ; i >= 0; i -- ) {
putchar(change(A[i])); // 将其他类型转换为char型
}
return 0;
}
方法二:利用ASCII码表大小字母转换法
核心代码
if(m > 9) str[k ++ ] = 'A' + m - 10;
else str[k ++ ] = '0' + m;
具体代码
#include<iostream>
#include<stdlib.h>
using namespace std;
// 方法二:简便法
typedef long long LL;
LL count;
char str[100];
int k = 0;
int main() {
scanf("%d",&count);
if(count == 0) printf("0");
while(count > 0) {
int m = count % 16;
count /= 16;
if(m > 9) str[k ++ ] = 'A' + m - 10;
else str[k ++ ] = '0' + m;
}
for(int i = k - 1; i >= 0; i -- ) printf("%c",str[i]);
return 0 ;
}
11.十六进制转十进制
(1)题目
(2) 代码
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long LL;
string str;
int main() {
cin >> str;
int length = str.length() ;
LL num = 0;
LL r = 1;
for(int i = length - 1; i >= 0; i --) {
if(str[i] >= '0' && str[i] <= '9') {
num += (str[i] - '0') * r;
r *= 16;
}
else {
num += (str[i] - 'A' + 10) * r;
r *= 16;
}
}
cout<< num;
return 0;
}
🔺12. 十六进制转八进制
(1)题目
(2)代码
思路
整体思路:先将16进制转换为二进制,再把二进制转换为8进制
注意:因为最后一个测试数据非常大 并且方便 前导0的去除,用c++string比较方便
#include<iostream>
#include<stdio.h>
#include<string>
using namespace std;
/* 整体思路:先将16进制转换为二进制,再把二进制转换为8进制 */
/* 注意:因为最后一个测试数据非常大 + 前导0的去除,用c++string比较方便*/
int main(){
int n; // 行数
cin>>n;
if(n < 1 || n > 10) return -1;
string hexadecimal, // 16进制
binary, // 二进制
octal; // 八进制
for(int i = 0; i < n; i++){
binary = "";
octal = "";
cin >> hexadecimal;
if(hexadecimal.length() > 100000) return -1;
/* 把16进制转换为二进制 */
/* 思路:先把16进制字符串全部转换成对应二进制字符串,输入一个转换一个 */
for(int j = 0; j < hexadecimal.size(); j++){
switch(hexadecimal[j]){
case '0' : binary += "0000"; break;
case '1' : binary += "0001"; break;
case '2' : binary += "0010"; break;
case '3' : binary += "0011"; break;
case '4' : binary += "0100"; break;
case '5' : binary += "0101"; break;
case '6' : binary += "0110"; break;
case '7' : binary += "0111"; break;
case '8' : binary += "1000"; break;
case '9' : binary += "1001"; break;
case 'A' : binary += "1010"; break;
case 'B' : binary += "1011"; break;
case 'C' : binary += "1100"; break;
case 'D' : binary += "1101"; break;
case 'E' : binary += "1110"; break;
case 'F' : binary += "1111"; break;
}
}
/* 16进制转换成2进制后填0 */
int binary_length = binary.size();
// 差2位补2个0
if(binary_length % 3 == 1){
binary = "00" + binary;
binary_length += 2;
}
// 差1位补1个0
if(binary_length % 3 == 2){
binary = "0" + binary;
binary_length++;
}
// 将二进制转换为8进制
for(int k = 0; k < binary_length; k += 3) {
int o = 4 * (binary[k] - '0') + 2 * (binary[k + 1] - '0') + (binary[k + 2] - '0');
octal += (o + '0');
}
// 去除前导0
int p = 0;
while(octal[p] == '0') p++;
// 输出
for(; p < octal.size(); p++) cout << octal[p];
cout << endl;
}
return 0;
}
13.数列排序
(1)题目
(2)代码
方法一:c++sort排序
#include<iostream>
#include<stdio.h>
#include<string>
#include<vector>
#include<cmath>
#include<math.h>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int n;
int a[N],temp[N];
int main() {
scanf("%d",&n);
if(n < 1 || n > 200) return -1;
for(int i = 0; i < n ; i ++ ) {
scanf("%d",&a[i]);
if(fabs(a[i] > N)) return -1;
}
sort(a,0,n - 1);
for(int i = 0; i < n; i++) {
printf("%d ",a[i]);
}
return 0;
}
方法二:归并排序(O(nlogn))
归并排序模板
const int N = 1e6 + 10;
int n;
int q[N], temp[N];
// 归并排序
void merge_sort(int q[],int l,int r) {
if(l >= r) return;
int mid = l + r >> 1; // >>相当于/2
merge_sort(q,l,mid),merge_sort(q,mid + 1, r); //递归排序,分别递归左右边
int k = 0,i = l,j = mid + 1;
// 归并
while(i <= mid && j <= r) { // 先在中点两边分别比较并升序
if(q[i] <= q[j]) temp[k++] = q[i++];
else temp[k++] = q[j++];
}
// 防止一边已经排序完成,另一边还没排序完,所以把另一边继续排序
while(i <= mid) temp[k++] = q[i++];
while(j <= r) temp[k++] = q[j++];
// 将排好序的值再赋给q[]
for(i = l, j = 0; i <= r; i++,j++) q[i] = temp[j];
}
具体代码
#include<iostream>
#include<stdio.h>
#include<string>
#include<vector>
#include<cmath>
#include<math.h>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int n;
int a[N],temp[N];
// 归并排序
void merge_sort(int q[],int low,int high) {
if(low >= high) return;
int mid = (low + high) / 2;
merge_sort(q,low,mid),merge_sort(q,mid + 1,high);
int k = 0, i = low, j = mid + 1;
while(i <= mid && j <= high) {
if(q[i] < q[j]) temp[k ++ ] = q[i ++ ];
else temp[k ++ ] = q[j ++ ];
}
while(i <= mid) temp[k ++ ] = q[i ++ ];
while(j <= high) temp[k ++ ] = q[j ++ ];
for(i = low,j = 0; i <= high; i ++, j ++ ) q[i] = temp[j];
}
int main() {
scanf("%d",&n);
if(n < 1 || n > 200) return -1;
for(int i = 0; i < n ; i ++ ) {
scanf("%d",&a[i]);
if(fabs(a[i] > N)) return -1;
}
merge_sort(a,0,n - 1);
for(int i = 0; i < n; i++) {
printf("%d ",a[i]);
}
return 0;
}
方法三:快速排序(超时但是不知道原因,按理说快排和归并同样时间复杂度,希望有大佬看见回答下)
快速排序模板
const int N = 1e6 + 10;
int n;
int q[N];
// 快速排序
void quick_sort(int q[],int l,int r) {
if(l >= r) return; // 判边界只有一个数时返回空
int x = q[l + r >> 1], i = l - 1, j = r + 1; // 取分界点x,两头指针i,j
while(i < j) { // 循环迭代,只要i,j未相遇,i往右走,j往左走
do i++; while(q[i] < x);
do j--; while(q[j] > x);
if(i < j) swap(q[i],q[j]);
// 若所用语言没有swap
// {
// int t = q[i];
// q[i] = q[j];
// q[j] = t;
// }
}
/*这种情况只能int x = q[l]去左边界,若int x = q[r]取右边界也会造成无限递归死循环
*/
quick_sort(q,l,j); // 左边界排序
quick_sort(q,j + 1,r); // 右边界排序
/*此处换成i也可以,但要注意对称
且上面int x = q[l]处要改为int x = q[(l + r +1) / 2]
(原因是若保持int x = q[l]会造成无限递归死循环)
quick_sort(q,l,i - 1); // 左边界排序
quick_sort(q,i,r); // 右边界排序
*/
}
具体代码
#include<iostream>
#include<stdio.h>
#include<string>
#include<vector>
#include<cmath>
#include<math.h>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int n;
int a[N],temp[N];
// 快速排序
void quick_sort(int q[],int low,int high) {
if(low >= high) return;
int mid = q[low + high >> 1], i = low - 1, j = high + 1;
while(i < j) {
do i ++ ; while(q[i] < mid);
do j -- ; while(q[j] > mid);
if(i < j) {
int temp = q[i];
q[i] = q[j];
q[j] = temp;
}
}
quick_sort(q,low,j);
quick_sort(q,j,high);
}
int main() {
scanf("%d",&n);
if(n < 1 || n > 200) return -1;
for(int i = 0; i < n ; i ++ ) {
scanf("%d",&a[i]);
if(fabs(a[i] > N)) return -1;
}
quick_sort(a,0,n - 1); // 快速排序
for(int i = 0; i < n; i++) {
printf("%d ",a[i]);
}
return 0;
}
14.时间转换
(1)题目
(2)代码
#include<iostream>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
LL n;
int main() {
scanf("%d",&n);
int hours = n / 3600;
int minutes = n % 3600 / 60;
int seconds = n % 60;
cout << hours << ":" << minutes << ":" << seconds;
return 0;
}
15.字符串对比
(1)题目
(2)代码
知识点1:string类型可以直接比较是否相等
if(str1 == str2) cout<< "2";
知识点2:string.end(),string.begin()函数
begin()函数,返回一个迭代器,指向字符串的第一个元素。
end()函数,也是返回一个迭代器,指向字符串末尾(最后一个字符的后一个位置)。
迭代器本质为指针,但如果要取元素,必须加*去元素
--------------------------------------------------------------------------
string str = "What";
cout << "str.begin(): " << *(str.begin()) << endl;
cout << "str.end(): " << *(str.end()-1) <<endl;
---------------------------------------------------------------------------
str.begin(): W
str.end(): t
知识点3:string类型字符串转换大小写方法
// 注意:头文件#include<algorithm>
string src = "Hello World!";
string dst;
// 转换大写
transform(src.begin(), src.end(), back_inserter(dst), ::toupper);
cout << dst << endl;
// 转换小写
transform(src.begin(), src.end(), dst.begin(), ::tolower);
cout << dst << endl;
知识点4:普通字符/字符数组转换方法
char change(char a[]) {
for(int i = 0; a[i] != '\0'; i ++ ) {
// 转换大写
if(a[i] >= 'a' && a[i] <= 'z'){ //判断是否在小写字母范围内
a[i] -= 32;
}
// 转换小写
if(a[i] >= 'A' && a[i] <= 'Z') {
a[i] += 32;
}
puts(a);
}
}
具体代码
#include<iostream>
#include<cstring>
#include<string.h>
#include<ctype.h>
#include<bits/stdc++.h>
#include<algorithm>
using namespace std;
typedef long long LL;
string str1;
string str2;
int i = 0;
int flag = 0;
int main() {
ios::sync_with_stdio(false); // 让cin尽量变得和scanf()一样快,但还是会比scanf()慢点
cin >> str1;
cin >> str2;
// 第一种情况
if(str1.length() != str2.length()) cout << "1";
else {
// 第二种情况
/* 知识点:string类型可以直接比较是否相等 */
if(str1 == str2) cout<< "2";
// 方法二:也可逐个比较字符串内的每个字符
/*
while(str1[i] == str2[i]) {
i ++ ;
if(*(str1.end() - 1) && *(str2.end() - 1)) flag = 1;
}
if(flag) cout << "2";
flag = 0;
*/
else {
string str11;
string str22;
// string类型转换大写方法
transform(str1.begin(), str1.end(), back_inserter(str11), ::toupper);
transform(str2.begin(), str2.end(), back_inserter(str22), ::toupper);
// 第三种情况
if(str11 == str22) {
cout << "3";
}
// 第四种情况
else cout << "4";
}
}
return 0;
}
16.分解质因数
(1)题目
(2)代码
#include<iostream>
#include<cstring>
#include<string.h>
#include<ctype.h>
#include<bits/stdc++.h>
#include<algorithm>
using namespace std;
typedef long long LL;
int a,b;
// 分解质因数模板
// 暴力做法
void divide(int n) {
for(int i = 2; i <= n; i ++ ) {
// 判断当前i(质因子)能否多次出现
while(n != i) {
if(n % i == 0) {
cout << i << "*";
n /= i;
}
else break;
}
}
cout << n << endl;
}
int main () {
scanf("%d%d",&a,&b);
for(int i = a; i <= b; i ++ ) {
cout << i << "=";
divide(i);
}
return 0;
}
17.矩阵乘法
(1)题目
(2)代码
知识点:矩阵乘法运算律
c[i][j] += b[i][k] * a[k][j]; // 矩阵乘法运算法则,b[i][j]代表着上一次的高次幂
#include<iostream>
using namespace std;
int a[30][30],b[30][30],c[30][30];
int n,m;
int main() {
scanf("%d%d",&n,&m);
for(int i = 0; i < n; i ++ ) {
for(int j = 0; j < n; j ++ ) {
cin >> a[i][j];
b[i][j] = a[i][j];
c[i][j] = 0;
}
}
if(m == 0) {
for(int i = 0; i < n; i ++ ) {
for(int j = 0; j < n; j ++ )
if(i == j) b[i][j] = 1;
else b[i][j] = 0;
}
}
if(m > 0) {
while(-- m ) { // 必须 -- m
for(int i = 0; i < n; i ++ ) {
for(int j = 0; j < n; j ++ )
for(int k = 0; k < n; k ++ )
c[i][j] += b[i][k] * a[k][j]; // 矩阵乘法运算法则,b[i][j]代表着上一次的高次幂
}
for(int i = 0; i < n; i ++ ) {
for(int j = 0; j < n; j ++ ) {
b[i][j] = c[i][j]; // 把这次运算结果给b,当作下一次高次幂的条件
c[i][j] = 0; // c存放运算结果,每次赋值完都要清空
}
}
}
}
for(int i = 0; i < n; i ++ ) {
for(int j = 0; j < n; j ++ )
cout << b[i][j] << " ";
cout << endl;
}
return 0;
}
18.矩阵面积交
(1)题目
(2)代码
#include<iostream>
using namespace std;
double x1,x2,y1,y2,x3,x4,y3,y4;
double s;
double min(double a, double b) {
return a < b ? a : b;
}
double max(double a, double b) {
return a > b ? a : b;
}
int main() {
ios::sync_with_stdio(false);
cin >> x1 >> y1 >> x2 >> y2;
cin >> x3 >> y3 >> x4 >> y4;
double xmax = min(max(x1,x2),max(x3,x4));
double xmin = max(min(x1,x2),min(x3,x4));
double ymax = min(max(y1,y2),max(y3,y4));
double ymin = max(min(y1,y2),min(y3,y4));
if(xmax > xmin && ymax > ymin)
s = (xmax - xmin) * (ymax - ymin);
printf("%.2lf",s);
return 0;
}
19.完美的代价
(1)题目
(2)代码
题目解析:
(1)Impossible 的两种情况:
n为奇数时,如果已经有一个字符出现的次数为奇数,还找到了一个字符出现的次数为奇数,那么就不能构成回文串;
n为偶数时,只要找到有一个字符出现的次数为奇数,那么就不能构成回文串。
(2)题目中要求输出最小的交换次数,那么怎样才能保证交换次数最小呢?
如果 n 为偶数,那么从第一字符开始,从后往前找第一个和它相同的字符,如果找了,就将找到的字符交换到最后一个位置,在下一次遍历时,就可以不用管刚才已经交换好的那来两个字符;下一次从第二个字符开始,从倒数第二个字符开始遍历,执行和上述相同的操作;
如果 n 为奇数,在字符串的某一个位置找到了那个出现次数为奇数的字符,我们不必将次字符现在就交换到中间位置,而是先计算它到中间位置需要交换的次数,然后累加到 cnt 中,将剩下的字符都交换到对称后,再交换这个字符即可。
试着想一想,如果第一个字符就为出现次数为奇数的字符,那么将它交换到中间位置,接下来交换其他字符时,每次的交换次数都会多一次。这其实是一种普遍的规律。
#include<iostream>
using namespace std;
int n;
string s;
int main () {
cin >> n;
cin >> s;
int end = n - 1; // 字符串最后一个字符
int count = 0; // 交换次数
int oddNum = 0; // 判断是否已经有一个单独的奇个数的字符了
/*如果 n 为偶数,那么从第一字符开始,从后往前找第一个和它相同的字符,
如果找了,就将找到的字符交换到最后一个位置,在下一次遍历时,就可以不用管刚才已经交换好的那来两个字符;
下一次从第二个字符开始,从倒数第二个字符开始遍历,执行和上述相同的操作;*/
for(int i = 0; i < end; i ++ ) { // 从第一个字符到倒数第二个字符遍历
for(int j = end; j >= i; j -- ) { // 从最后一个开始,到第i个字符,寻找与s[i]相同的字符
if(i == j) {
// n为偶数时,只要找到有一个字符出现的次数为奇数,那么就不能构成回文串。
// n为奇数时,如果已经有一个字符出现的次数为奇数,还找到了一个字符出现的次数为奇数,那么就不能构成回文串;
if(n % 2 == 0 || oddNum == 1) {
cout << "Impossible";
return 0;
}
/*
如果 n 为奇数,在字符串的某一个位置找到了那个出现次数为奇数的字符,
我们不必将次字符现在就交换到中间位置,而是先计算它到中间位置需要交换的次数,
然后累加到 cnt 中,将剩下的字符都交换到对称后,再交换这个字符即可。
*/
oddNum = 1; // 找到一个字符出现的次数为奇数
count += n / 2 - i; // 将次字符交换到中间位置的次数
}
else if(s[i] == s[j]) { // 如果找到了,将s[j]交换到s[end]位置
for(int k = j; k < end; k ++ ) { // 交换相邻两个位置的字符
swap(s[k],s[k + 1]);
count ++;
}
end -- ; // 末尾递减
break; // 开始从i+1处重复操作
}
}
}
cout << count;
return 0;
}