22,23年蓝桥杯
洛谷---Z字形变换
将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:
P A H N
A P L S I I G
Y I R
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
点击查看代码
class Solution {
public:
string convert(string s, int numRows) {
if(numRows<2) return s;
vector<string> n(numRows);
int i=0,flag=-1;
for(char c:s)
{
n[i].push_back(c);
if(i==0||i==numRows-1)
{
flag=-flag;
}
i+=flag;
}
string res;
for(const string &b:n)
{
res+=b;
}
return res;
}
};
思路:
字符串 s 是以 Z 字形为顺序存储的字符串,目标是按行打印。
设 numRows 行字符串分别为 s 1 , s 2 , … , s n ,则容易发现:按顺序遍历字符串 s 时,每个字符 c 在 N 字形中对应的 行索引 先从 s 1 增大至 s n ,再从 s 减小至 s 1 …… 如此反复。因此解决方案为:模拟这个行索引的变化,在遍历 s 中把每个字符填到正确的行 res[i] 。
按顺序遍历字符串 s :res[i] += c: 把每个字符 c 填入对应行 s i ;i += flag: 更新当前字符 c 对应的行索引;flag = - flag: 在达到 Z 字形转折点时,执行反向。
2023年蓝桥杯 第二题:顺子日期
问题描述:
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小明特别喜欢顺子。顺子指的就是连续的三个数字:123、456 等。顺子日期指的就是在日期的 yyyymmdd 表示法中,存在任意连续的三位数是一个顺子的日期。例如 20220123 就是一个顺子日期,因为它出现了一个顺子:123; 而 20221023 则不是一个顺子日期,它一个顺子也没有。小明想知道在整个 2022 年份中,一共有多少个顺子日期?
点击查看代码
#include<iostream>
#include<string>
using namespace std;
bool cheak(int year,int month,int day)
{
string str=to_string(year);
if(month<10) str+='0';
str+=to_string(month);
if(day<10) str+='0';
str+=to_string(day);
return (str.find("012")!=str.npos)||(str.find("123")!=str.npos);//等同于str.find("012")!=-1
}
int main()
{
int year=2022;
int i,j;
int ans=0;
int months[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
for(i=1;i<=12;i++)
{
for(j=1;j<=months[i];j++)
{
if(cheak(year,i,j)==true)
{
ans++;
}
}
}
cout<<ans<<endl;
return 0;
}
思路:
字符串解题
解题思路:枚举 2022 年所有的日期,然后判断是否存在顺子即可。
本题的顺子为顺序的三位数,包括 012,123,234,345,456,567,678,789。由于是 2022 年的日期,顺子只可能是 012 和 123,其余顺子不可能出现,因为其余均为非法日期。
最终只需枚举月、日,然后 check 一下每个日期中是否存在上述顺子即可。
第三题:修剪灌木
问题描述:
爱丽丝要完成一项修建灌木的工作。有N棵灌木整齐的从左到右排成一排。爱丽丝在每天傍晚会修剪一棵灌木,让灌木的高度变为0厘米。爱丽丝修剪灌木的顺序是从最左侧的灌木开始,每天向右修剪一棵灌木。当修剪了最右侧的灌木后,它会调转方向,下一天开始向左修剪灌木,直到修剪了最左的灌木后再次调转方向。然后如此循环往复。灌木每天从早上到傍晚会长高1厘米,而其余时间不会长高。在第一天的早晨,所有灌木的高度都是0cm。爱丽丝想知道每颗灌木最高长到多高。
点击查看代码
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
int main()
{
int i,n,num;
int max[10000]={};
int left,right;
scanf("%d",&n);
sum=n-1;
for(i=0;i<=sum;i++)
{
left=i;
right=sum-i;
if(left<=right){
max[i]=2*right;
printf("%d\n",max[i]);
}
else if(left>right){
max[i]=2*left;
printf("%d\n",max[i]);
}
}
return 0;
还有另一种解法,假设点i刚被修剪完为0,然后会向右/向左跑一趟,端点会被遍历1次,i与端点间的点会被遍历两次
而重新修剪i的当天早上(因为是傍晚修剪,所以当天也会被算上)达到最大高度,然后置零
也就是说:最大长度=中间节点数*2+1(端点)+1(自生)==max(左边/右边节点数)*2
左边端点数:i-1
右边端点数:n-i
点击查看代码
#include <iostream>
using namespace std;
int main()
{
int n;
cin>>n;
for(int i = 1;i<=n;i++) cout<<max(i-1,n-i)*2<<endl;
return 0;
}
第一题:九进制转十进制
问题描述
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
点击查看代码
#include <iostream>
#include<cstdlib>
#include<bitset>
using namespace std;
int solution()
{
int a=2+2*9+2*9*9*9;
cout<<a;
return 0;
}
int main()
{
solution();
return 0;
}
思路:
直接暴力。
第五题:X格式进制
X 进制减法
问题描述:
进制规定了数字在数位上逢几进一。
XX 进制是一种很神奇的进制, 因为其每一数位的进制并不固定!例如说某 种 XX 进制数, 最低数位为二进制, 第二数位为十进制, 第三数位为八进制, 则 XX 进制数 321 转换为十进制数为 65 。
现在有两个 XX 进制表示的整数 AA 和 BB, 但是其具体每一数位的进制还不确 定, 只知道 AA 和 BB 是同一进制规则, 且每一数位最高为 NN 进制, 最低为二进 制。请你算出 A−BA−B 的结果最小可能是多少。
请注意, 你需要保证 AA 和 BB 在 XX 进制下都是合法的, 即每一数位上的数 字要小于其进制。
输入格式:
第一行一个正整数 NN, 含义如题面所述。
第二行一个正整数 MaM a , 表示 XX 进制数 AA 的位数。第三行 MaM a 个用空格分开的整数, 表示 XX 进制数 AA 按从高位到低位顺序各 个数位上的数字在十进制下的表示。
第四行一个正整数 MbM b , 表示 XX 进制数 BB 的位数。第五行 MbM b 个用空格分开的整数, 表示 XX 进制数 BB 按从高位到低位顺序各 个数位上的数字在十进制下的表示。
请注意, 输入中的所有数字都是十进制的。
输出格式:
输出一行一个整数, 表示 XX 进制数 A−BA−B 的结果的最小可能值转换为十进制后再模 100000000的。
点击查看代码
#include <iostream>
using namespace std;
const int mod=10000000072,M=1e5+10;
int main()
{
int N;
int min=0;
long long a[M];
long long b[M];
long long p[M];
long long w[M];
long long A,B;
return 0;
}
int main()
{
cin>>n;
cin>>ma;
for(int i=ma-1;i>=0;i--)
{
cin>>a[i];
}
cin>>mb;
for(int i=mb-1;i>=0;i--)
{
cin>>a[i];
}
int we=max(ma,mb);
for(itn i=0;i<we;i++)
{
int t=max(a[i],b[i]);
p[i]=max(2,t+1);
}
w[0]=1;
for(int i=0;i<we;i++)
{
w[i]=p[i-1]*w[i-1]%mod;
}
for(int i=ma-1;i>=0;i--)
{
A=(A+a[i]*w[i])%mod;
}
cout<<(A-B+mod)%mod<<endl;
return 0;
}
思路:
用数组记录a,b的每一位数,再用两个数据去分别记录每一位的进制和权重。
然后输入数组a,b,A和B的位数不一定相等,所以说取较大的那个,然后对于没有数值的位,补0,计算权重前缀和:p[i] * p[i-1] * p[i-2] * ...,将A和B在X进制下的每位数转换成十进制,将 A 在X进制下的每一位转换成十进制,然后 A 整体转化为 十进制数,将 B 在X进制下的每一位转换成十进制;然后 B 整体转化为 十进制数,最后取模输出。
22年 第一题:空间
空间
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小蓝准备用 256MB256MB 的内存空间开一个数组,数组的每个元素都是 3232 位 二进制整数,如果不考虑程序占用的空间和维护内存需要的辅助空间,请问 256MB的空间可以存储多少个 3232 位二进制整数?
点击查看代码
#include <iostream>
using namespace std;
int main()
{
cout<<256*1024*1024/4<<endl;
return 0;
}
22年第二题:卡片
问题描述
小蓝有 k 种卡片, 一个班有 n 位同学, 小蓝给每位同学发了两张卡片, 一 位同学的两张卡片可能是同一种, 也可能是不同种, 两张卡片没有顺序。没有 两位同学的卡片都是一样的。
给定 n, 请问小蓝的卡片至少有多少种?
输入格式
输入一行包含一个正整数表示 n。
输出格式
输出一行包含一个整数, 表示答案。
点击查看代码
#include<iostream>
using namespace std;
int solution1()
{
int n, m;
cin >> n;
int ans = 0;
for (int i = 1;i>0; i++)
{
ans += i;
if (ans >= n) {
m = i;
break;
}
}
cout << m << endl;
return 0;
}
int main()
{
solution1();
}
思路:
找规律累加到几的和大于人数时,输出累加的最后一个数。
22年第三题:直线
问题描述:
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上, 那么这些点中任意两点确定的直线是同一条。
给定平面上 2 × 3 个整点(x,y)∣0≤x<2,0≤y<3,x∈Z,y∈Z,即横坐标 是 0 到 1 (包含 0 和 1) 之间的整数、纵坐标是 0 到 2 (包含 0 和 2) 之间的整数 的点。这些点一共确定了 11 条不同的直线。
给定平面上 20×21,20×21 个整点 (x,y)∣0≤x<20,0≤y<21,x∈Z,y∈Z(x,y)∣0≤x<20,0≤y<21,x∈Z,y∈Z,即横 坐标是 0 到 19 (包含 0 和 19) 之间的整数、纵坐标是 0 到 20 (包含 0 和 20) 之 间的整数的点。
请问这些点一共确定了多少条不同的直线。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef pair<double, double> PII;
const int N = 20, M = 21;
set<PII> st;
void check(int x1, int y1, int x2, int y2) {
if (x1 == x2 || y1 == y2) return;
double k = (y2 - y1) * 1.0 / (x2 - x1);
double b = (y1*x2 - x1*y2) * 1.0 / (x2 - x1);
st.insert({k, b});
}
int main() {
for (int i = 0; i < N; i ++)
for (int j = 0; j < M; j ++)
for (int k = 0; k < N; k ++)
for (int l = 0; l < M; l ++)
check(i, j, k, l);
cout << st.size() + N + M <<endl;
return 0;
}
思路:
两点确定一条直线,而只需要同时对斜率和截距去重,就能判断两条直线是否是同一直线:如果两条直线的斜率相等,并且截距也相等,就说明是同一条直线。与x轴或者y轴平行的直线另外计算。这样就得到了一个较清晰的思路:
生成所有点
判断所有两两点确定的直线,去重
有几个点需要注意别踩坑:
1.斜率和截距不一定是整数,用double
2.截距的计算
3.去重用set
4.坐标可以用pair
5.不要忘记最后加上与x轴或者y轴平行的直线
第四题:摆放货物
题目描述:
小蓝有一个超大的仓库,可以摆放很多货物。
现在,小蓝有 n 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。
小蓝希望所有的货物最终摆成一个大的长方体。即在长、宽、高的方向上分别堆
L、W、H 的货物,满足 n=L×W×H。给定 n,请问有多少种堆放货物的方案满足要求。
例如,当 n=4 时,有以下 6 种方案:
1×1×4、1×2×2、1×4×1、2×1×2、2×2×1、4×1×1。
请问,当 n=2021041820210418 (注意有 16 位数字)时,总共有多少种方案?
提示:建议使用计算机编程解决问题。
点击查看代码
#include<iostream>
#include<cmath>
using namespace std;
typedef unsigned long long ll;
ll n = 2021041820210418;
ll a[3000], cnt = 0;
int main(void)
{
for(int i = 1; i <= sqrt(n); i++){
if(n % i == 0){
a[++cnt] = i;
if(i*i != n) a[++cnt] = n/i;
}
}
//循环
ll res = 0;
for(int l = 1; l <= cnt; l++)
for(int w = 1; w <= cnt; w++)
for(int h = 1; h <= cnt; h++)
if(a[l]*a[w]*a[h] == n) res++;
cout <<res;
return 0;
思路:
注意到 n = L×W×H这一条件,既然L、W、H相乘为n,那么L、W、H肯定都是n的因子。所以只要把n的全部因子找出来,然后找三个因子去充当长宽高,三重for循环就可以了。

浙公网安备 33010602011771号