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循环就可以了。

posted @ 2025-03-17 23:13  好好好好好好好好好  阅读(35)  评论(0)    收藏  举报