2022第十三届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组(题解解析)

news2025/4/8 6:35:42

记录刷题的过程、感悟、题解。
希望能帮到,那些与我一同前行的,来自远方的朋友😉


大纲:

 1、九进制转十进制-(解析)-简单的进制转化问题😄

 2、顺子日期-(解析)-考察日期

 3、刷题统计-(解析)-简单的除法问题🥲,千万别暴力,会超时

 4、修剪灌木-(解析)-真·贪心,主打一个观察能力🥲or 想象力

 5、X 进制减法-(解析)-进阶一点的进制转化,需要对进制转化,有更深层次的了解。

 6、统计子矩阵-(解析)-二维前缀和+滑动窗口,如果纯前缀和打暴力(只能过70%) 

 7、积木画-(解析)-太好了,我一直以为无解,原来能用线性dp做出来,太感动了(┬┬﹏┬┬),原来还能让人做。

 8、扫雷-(解析)-啊,这道题出乎意料的简单,出在倒数第三题,简直了😇,很多人都做不到呐。

 9、李白打酒加强版-(解析)-记忆化搜索+dfs,单纯dfs定超时。|| dp也能解决。

 10、砍竹子-(解析)-这道题真是智者见智了,八仙过海、各显神通。我用的优先队列。😉


题目:

1、九进制转十进制

问题描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

九进制正整数 (2022)9转换成十进制等于多少?

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 512M

本题就是一道,简单的进制转化题目

解析:(2022)9=2*9^0+2*9^1+0*9^2+2*9^

2是基数、9是进制数

#include <bits/stdc++.h>
using namespace std;
int main(){
	string str="2022";
	reverse(str.begin(),str.end());
	int sum=0;
	for(int i=0; i<str.size(); ++i){
		sum+=pow(9,i)*(str[i]-'0');
	}
	cout<<sum<<endl;
	return 0;
} 

2、顺子日期

问题描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

小明特别喜欢顺子。顺子指的就是连续的三个数字:123、456 等。顺子日期指的就是在日期的 yyyymmdd 表示法中,存在任意连续的三位数是一个顺子的日期。例如 20220123 就是一个顺子日期,因为它出现了一个顺子:123; 而 20221023 则不是一个顺子日期,它一个顺子也没有。小明想知道在整个 2022 年份中,一共有多少个顺子日期?

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 512M

本题,就写简单一点吧:"2022" 已经不可能与任何数 形成顺子了,可以直接排除掉

bool get_num(...)是用来判断,月日是否合理

bool get_cnt(...)是用来判断是否是顺子

#include <bits/stdc++.h>
using namespace std;
bool get_num(int mm, int dd){
  if(mm==1||mm==3||mm==5||mm==7||mm==8||mm==10||mm==12){// 31 天
    if(dd>=1&&dd<=31) return true;
  }else if(mm==2){ // 28天
    if(dd>=1&&dd<=28) return true;
  }else if(mm==4||mm==6||mm==9||mm==11){ // 30天
    if(dd>=1&&dd<=30) return true;
  } 
  return false;
}

bool get_cnt(string str){
	str = "9"+str; // 前面后缀一个数 
	vector<int> arr(str.size(),0);
	for(int i=1; i<str.size(); ++i)
		if(str[i]==str[i-1]+1) arr[i]=arr[i-1]+1; 
	for(int i=1; i<arr.size(); ++i) if(arr[i]==2) return true;
	return false;
}

int main()
{
  int sum=0;
  // 暴力。0100-1299 // 这些的吗?其实也能用递归深搜 
  for(int i=0; i<10; ++i){
    for(int j=0; j<10; ++j){
      for(int k=0; k<10; ++k){
        for(int z=0; z<10; ++z){ // 一共10层循环
          int mm = i*10+j;
          int dd = k*10+z;
          if(get_num(mm,dd)){
            string str =  to_string(i)+to_string(j)+to_string(k)+to_string(z);
            if(get_cnt(str)) sum++;
          }
        }
      }
    }
  }
  cout<<sum<<endl;
  return 0;
}

3、刷题统计

问题描述

小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天 做 a 道题目, 周六和周日每天做 b 道题目。请你帮小明计算, 按照计划他将在 第几天实现做题数大于等于 n 题?

输入格式

输入一行包含三个整数 a,b 和 n.

输出格式

输出一个整数代表天数。

样例输入

10 20 99

样例输出

8

评测用例规模与约定

对于 50% 的评测用例, 1≤a,b,n≤10^6.

对于 100% 的评测用例, 1≤a,b,n≤10^18.

// 哦草!本题大意了,没有看数据10^18次方呐,直接就开始暴力了。
// 本题没有必要开一个循环,一个一个加
// 能直接进行除法运算

#include <bits/stdc++.h>
#define int long long 
using namespace std;

signed main(){
	int a,b,n;
	cin>>a>>b>>n;
	int cnt = 0;
	int sum = n/(a*5+b*2);
	int temp = n%(a*5+b*2);
	if(temp<=a*5){
		cnt+=ceil((double)temp/a);	
	}else{
		temp-=5*a;
    cnt+=5;
		cnt+=ceil((double)temp/b);
	}  
	cnt+=sum*7;
	cout<<cnt<<endl;
	return 0;
}   

4、修剪灌木

问题描述

爱丽丝要完成一项修剪灌木的工作。

有 N 棵灌木整齐的从左到右排成一排。爱丽丝在每天傍晩会修剪一棵灌 木, 让灌木的高度变为 0 厘米。爱丽丝修剪灌木的顺序是从最左侧的灌木开始, 每天向右修剪一棵灌木。当修剪了最右侧的灌木后, 她会调转方向, 下一天开 始向左修剪灌木。直到修剪了最左的灌木后再次调转方向。然后如此循环往复。

灌木每天从早上到傍晩会长高 1 厘米, 而其余时间不会长高。在第一天的 早晨, 所有灌木的高度都是 0 厘米。爱丽丝想知道每棵灌木最高长到多高。

输入格式

一个正整数 N, 含义如题面所述。

输出格式

输出 N 行, 每行一个整数, 第 i 行表示从左到右第 i 棵树最高能长到多高。

样例输入

3

样例输出

4
2
4

评测用例规模与约定

对于 30% 的数据, N≤10.

对于 100% 的数据, 1<N≤10000.

// 本题大意了,其实挺好解决的。
// 最开始,我傻傻的,造了三个循环去解决本题,好愚蠢的呢,简单题,做麻烦 
// 其实脑子里面模拟一下,前面割着草,后面长着草,是不是有画面感了
// 一共n颗灌木,到第i颗灌木时:(n-i-1)*2 or i*2 颗 --取最大 
// 只是两个方向,从左向右时:i*2
//              从右向左时:(n-i-1)*2

#include <bits/stdc++.h>
using namespace std;

int main(){
	int n;
	cin>>n;
	vector<int> res(n,0);

	for(int i=0; i<n; ++i){
		res[i]=max(i*2,(n-i-1)*2);
	}

	for(int i:res) cout<<i<<endl;
	return 0;
}

5、X 进制减法

问题描述

进制规定了数字在数位上逢几进一。

X 进制是一种很神奇的进制, 因为其每一数位的进制并不固定!例如说某 种 X 进制数, 最低数位为二进制, 第二数位为十进制, 第三数位为八进制, 则 X 进制数 321 转换为十进制数为 65 。

现在有两个X 进制表示的整数 A 和 B, 但是其具体每一数位的进制还不确 定, 只知道 A 和 B 是同一进制规则, 且每一数位最高为 N 进制, 最低为二进 制。请你算出 A−B 的结果最小可能是多少。

请注意, 你需要保证 A 和 B 在 X 进制下都是合法的, 即每一数位上的数 字要小于其进制。

输入格式

第一行一个正整数 N, 含义如题面所述。

第二行一个正整数 Ma, 表示 X 进制数 A 的位数。

第三行 Ma​ 个用空格分开的整数, 表示 X 进制数 A 按从高位到低位顺序各 个数位上的数字在十进制下的表示。

第四行一个正整数 Mb​, 表示 X 进制数 B 的位数。

第五行 Mb​ 个用空格分开的整数, 表示 X 进制数 B 按从高位到低位顺序各 个数位上的数字在十进制下的表示。

请注意, 输入中的所有数字都是十进制的。

输出格式

输出一行一个整数, 表示 X 进制数 A−B 的结果的最小可能值转换为十进 制后再模 1000000007 的结果。

样例输入

11
3
10 4 0
3
1 2 0

样例输出

94

样例说明

当进制为: 最低位 2 进制, 第二数位 5 进制, 第三数位 11 进制时, 减法 得到的差最小。此时 A 在十进制下是 108, B 在十进制下是 14 , 差值是 94。

评测用例规模与约定

对于 30% 的数据, N≤10; Ma,Mb≤8.

对于 100% 的数据, 2≤N≤1000;1≤Ma​,Mb​≤100000;A≥B.

// 这是一道贪心题,读清楚题目之后,本题思路就会异常清晰。
// “两个数,共用一套X进制的规则”
// 质保保证两个数,尽可能的小就行
// 本题最重要的就是,进制转换的计算,
//(本位,前方所有进制相乘,就是此位置该乘的数)--> 举例:10*(2*5)+4*(2)+0*(0)=108 

#include <bits/stdc++.h>
#define int long long
const int CNT = 1000000007; 
using namespace std;

signed main(){
	int N;
	cin>>N;
	int an,bn;
	cin>>an;
	vector<int> A(an,0);
	for(int i=an-1; i>=0; --i) cin>>A[i];
	cin>>bn;
	vector<int> B(bn,0);
	for(int j=bn-1; j>=0; --j) cin>>B[j];
  int sum = 0;
  int X = 1;
  for(int i=0; i<an; ++i){
    sum=(sum+(A[i]-B[i])*X)%CNT;
    X *= max(A[i],B[i])<=1?2:max(A[i],B[i])+1;
    X%=CNT;
  }
	cout<<sum<<endl;
	 
	
	return 0;
} 

6、统计子矩阵

问题描述

给定一个 N×M 的矩阵 A, 请你统计有多少个子矩阵 (最小 1×1, 最大 N×M) 满足子矩阵中所有数的和不超过给定的整数 K ?

输入格式

第一行包含三个整数 N,M 和 K.

之后 N 行每行包含 M 个整数, 代表矩阵 A.

输出格式

一个整数代表答案。

样例输入

3 4 10
1 2 3 4
5 6 7 8
9 10 11 12

样例输出

19

样例说明

满足条件的子矩阵一共有 19 , 包含:

大小为 1×1 的有 10 个。

大小为 1×2 的有 3 个。

大小为 1×3 的有 2 个。

大小为 1×4 的有 1 个。

大小为 2×1 的有 3 个。

评测用例规模与约定

对于 30% 的数据, N,M≤20.

对于 70% 的数据, N,M≤100.

对于 100%的数据, 1≤N,M≤500;0≤Aij≤1000;1≤K≤250000000

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

本质上就是一道二维前缀和+滑动窗口的集合,如果只用二维前缀和的话只能过70%

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e2 + 5;
int arr[N][N]; 
int n, m, K;

signed main() {
    // 输入矩阵的行数、列数和阈值 K
    cin >> n >> m >> K;
    // 输入矩阵元素
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            cin >> arr[i][j];
    // 计算每行的前缀和
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            arr[i][j] += arr[i][j - 1];
    // 计算每列的前缀和,得到二维前缀和
    for (int j = 1; j <= m; ++j)
        for (int i = 1; i <= n; ++i)
            arr[i][j] += arr[i - 1][j];
	int cnt=0;
	// 上边界 
   	for(int top=0; top<=n; ++top){
   		// 下边界 
   		for(int bott=top+1; bott<=n; ++bott){
   			// 左上边界 
   			int l=0; 
   			// 右上边界 
   			for(int r=1; r<=m; ++r){
   				int sum= arr[bott][r]-arr[bott][l]-arr[top][r]+arr[top][l];	
				while(sum>K&&l<r){
					l++;
					sum= arr[bott][r]-arr[bott][l]-arr[top][r]+arr[top][l];
				}
				cnt+=r-l;
			}
		}	
	}
	 
    // 输出结果
    cout << cnt << endl;
    return 0;
}    

7、积木画

问题描述

小明最近迷上了积木画, 有这么两种类型的积木, 分别为 I 型(大小为 2 个单位面积) 和 L 型 (大小为 3 个单位面积):

同时, 小明有一块面积大小为 2×N 的画布, 画布由 2×N 个 1×1 区域构成。小明需要用以上两种积木将画布拼满, 他想知道总共有多少种不同的方式? 积木可以任意旋转, 且画布的方向固定。

输入格式

输入一个整数 N,表示画布大小。

输出格式

输出一个整数表示答案。由于答案可能很大,所以输出其对 1000000007 取模后的值。

样例输入

3

样例输出

5

样例说明

五种情况如下图所示,颜色只是为了标识不同的积木:

评测用例规模与约定

对于所有测试用例,1≤N≤10000000.

运行限制

  • 最大运行时间:3s
  • 最大运行内存: 512M

注:其实很久很久之前,我是很恐惧这种题型的,因为我觉得无解
        现在发现,竟然能用动态规划解决,那实在太幸福了。毕竟难总比无解好

// 很多人说,本题是状态压缩,其实按照线性dp的思路就能解决。
// 说到动态规划,大家都清楚,是由前方状态推出后方状态
// 当然啦,还有每个状态的意义,状态推导公式、初始化,遍历顺序
/*
    每个状态的意义:!!一定要看清楚 
    dp[i][0] ,第i列,只有第一行被填满
    dp[i][2] ,第i列,只有第二行被填满
    dp[i][1] ,第i列,两整行都被填满 
*/ 
/*
    状态推导公式:
    dp[i][0]
    如果要使第一行能被填满,有两种可能,上一列为dp[i-1][2],于是可以横放一个I型
     还有一种可能是,上上一列 为dp[i-2][1],这种情况下,可以放置一个L型   
     于是推导出 dp[i][0]= dp[i-1][2]+dp[i-2][1];
     
     dp[i][2]
     上一列为dp[i-1][0],上一列,第一行有东西,此刻,就能横向放置I型
    上上一列为dp[i-2][1],这种情况下,可以放置一个L型 
    于是推导出 dp[i][2]=dp[i-1][0]+dp[i-2][1];
    
    dp[i][1]
    本列想要填满,只有可能为dp[i-1][0] or dp[i-1][2],本列可以放置L型
    dp[i-1][1](上一列被填满),本列可以放置I型
    dp[i-2][1](上上一列被填满),那可以置换成两个L型 
    dp[i][1]=dp[i-1][0] + dp[i-1][2] + dp[i-1][1] + dp[i-2][1];
*/ 

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MOD = 1000000007; 
const int N = 1e7+5;
// vector<vector<int>> dp(N,vector<int>(3,0));
int dp[N][3];


signed main(){
	int n;
	cin>>n;	
	dp[0][1]=1; // 只能竖放一个I 
	dp[1][1]=1; // 只能竖放一个I ,这个才是真正的第一列。
	
  for(int i=2; i<=n; ++i){
		dp[i][0]=(dp[i-1][2]+dp[i-2][1])%MOD;
		dp[i][2]=(dp[i-1][0]+dp[i-2][1])%MOD;
		dp[i][1]=((dp[i-1][0] + dp[i-1][2])%MOD + (dp[i-1][1] + dp[i-2][1])%MOD)%MOD;
	} 

	cout<<dp[n][1]<<endl;
	return 0;
} 

8、扫雷

题目描述

在一个 n 行 m 列的方格图上有一些位置有地雷,另外一些位置为空。

请为每个空位置标一个整数,表示周围八个相邻的方格中有多少个地雷。

输入描述

输入的第一行包含两个整数 n,m。

第 2 行到第 n+1 行每行包含 m 个整数,相邻整数之间用一个空格分隔。如果对应的整数为 0,表示这一格没有地雷。如果对应的整数为 1,表示这一格有地雷。

其中,1≤n,m≤100 分钟后还是在当天。

输出描述

输出 n 行,每行 m 个整数,相邻整数之间用空格分隔。

对于没有地雷的方格,输出这格周围的地雷数量。对于有地雷的方格,输出 9。

输入输出样例

示例 1

输入

3 4
0 1 0 0
1 0 1 0
0 0 1 0

输出

2 9 2 1
9 4 9 2
1 3 9 2

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 128M

本题意想不到的简单,我人傻了。 

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e2+5;
vector<vector<int>> arr(N,vector<int>(N,0));
// 看到这道题目,我有点炸了,这道题目,咋这么简答😥,不是哥们,这可是倒数第三题呢。
//int arr[N][N];
//int res[N][N];
vector<vector<int>> res(N,vector<int>(N,0));
int n,m;
int fa1[]={1,1,0,0,-1,1,-1,-1};
int fa2[]={-1,1,1,-1,0,0,1,-1};

signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1; i<=n; ++i)
		for(int j=1; j<=m; ++j) cin>>arr[i][j];
	// 真嘟假嘟
	for(int i=1; i<=n; ++i){
		for(int j=1; j<=m; ++j){
			if(arr[i][j]!=0) res[i][j]=9;
			else{
				int sum=0;
				for(int k=0; k<8; ++k){
					if(arr[i+fa1[k]][j+fa2[k]]!=0) sum++;
				}
				res[i][j]=sum;
			}
		}
	}
	for(int i=1; i<=n; ++i){
		for(int j=1; j<=m; ++j) cout<<res[i][j]<<" ";
		cout<<endl;
	}
	return 0;
}

9、李白打酒加强版

问题描述

话说大诗人李白, 一生好饮。幸好他从不开车。

一天, 他提着酒显, 从家里出来, 酒显中有酒 2 斗。他边走边唱:

无事街上走,提显去打酒。 逢店加一倍, 遇花喝一斗。

这一路上, 他一共遇到店 N 次, 遇到花 M 次。已知最后一次遇到的是花, 他正好把酒喝光了。

请你计算李白这一路遇到店和花的顺序, 有多少种不同的可能?

注意: 显里没酒 ( 0 斗) 时遇店是合法的, 加倍后还是没酒; 但是没酒时遇 花是不合法的。

输入格式

第一行包含两个整数 N 和 M.

输出格式

输出一个整数表示答案。由于答案可能很大,输出模 1000000007 的结果.

样例输入

5 10

样例输出

14

样例说明

如果我们用 0 代表遇到花,1 代表遇到店,14 种顺序如下:

010101101000000

010110010010000

011000110010000

100010110010000

011001000110000

100011000110000

100100010110000

010110100000100

011001001000100

100011001000100

100100011000100

011010000010100

100100100010100

101000001010100

评测用例规模与约定

对于 40% 的评测用例: 1≤N,M≤10。

对于 100% 的评测用例: 1≤N,M≤100 。

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M
记忆化搜索+递归
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 1000000007;
int used[105][105][105]; 
int n,m,drink;
// 不论是递归,还是动规,都是推到至,上一种状态 
int dfs(int n,int m,int drink){
	if(n<0||m<0||drink<0) return 0;
	if(drink>m) return 0;
	if(n==0&&m==1&&drink==1) return 1; // 一切刚刚好 
	
	// 记忆化搜索 
	if(used[n][m][drink]!=-1) return used[n][m][drink]; // 记忆化搜索,代表遍历过 
	else {
		return used[n][m][drink]=(dfs(n-1,m,drink*2)+dfs(n,m-1,drink-1))%MOD; 
	}
	
}
signed main(){
	cin>>n>>m;
	memset(used,-1,sizeof used); // 统一初始化,助力记忆化搜索 
	drink = 2;
	cout<<dfs(n,m,drink); 
	return 0;
}
动态规划
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 1000000007;
int n,m;
int dp[105][105][105];

signed main(){
	cin>>n>>m;
    // 初始状态是:经过了0家店、0家花、有2壶酒。

    // 其实,就是由两个状态推导出来的
    /*
     * dp[n][m][k]: 酒店 dp[n-1][m][drink/2] 他的上一种状态,可能已经经过n-1店、m家花、拥有drink/2个酒
     * dp[n][m][k]:花店 dp[n][m-1][drink+1] 他的上一种状态,可能经过n家店、m-1家花、拥有drink+1杯酒
    */
    dp[0][0][2]=1; // 这是一种可能
    for(int i=0; i<=n; ++i){
        for(int j=0; j<=m; ++j){ 
            for(int k=0; k<=m; ++k){
                if(j>0 && k>0) dp[i][j][k]=dp[i][j-1][k+1];
                if(i>0 && k%2==0) dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k/2])%MOD;
            }
        }
    }
    cout<<dp[n][m-1][1]<<endl;
	return 0;
}

10、砍竹子

问题描述

这天, 小明在砍竹子, 他面前有 n 棵竹子排成一排, 一开始第 i 棵竹子的 高度为 hi​.

他觉得一棵一棵砍太慢了, 决定使用魔法来砍竹子。魔法可以对连续的一 段相同高度的竹子使用, 假设这一段竹子的高度为 H, 那么

用一次魔法可以 把这一段竹子的高度都变为 ⌊⌊H2⌋+1⌋, 其中 ⌊x⌋ 表示对 x 向下取整。小明想 知道他最少使用多少次魔法可

让所有的竹子的高度都变为 1 。

输入格式

第一行为一个正整数 n, 表示竹子的棵数。

第二行共 n 个空格分开的正整数 hi​, 表示每棵竹子的高度。

输出格式

一个整数表示答案。

样例输入

6
2 1 4 2 6 7

样例输出

5

样例说明

// 灵感:暴力解法,去最大,找连续,并及时删除 
// 我忘记了,向上取整,是个啥玩意?? 
// 哪我就斗胆,用一次优先队列,在具体看一下,优先队列的用法
/*
  本题,其实最抽象的就是sqrtl---应用,因为本题最大特色就是,数字有10^18次方这么大,而double只用10^16~17这么大。
  为啥本题我选择了优先队列!毕竟本题是一道贪心题,找规则呗,下方样例说明中,提示,竹子,是从最高处开始砍的。
  优先队列不就是这么玩的吗😄?
  然后,又因为能使用魔法(本质就是,坐标相邻,大小相同的数组....
  所以一看就要引入pair<int,int>,当然struct也行。两者构造的时间与占用的空间都差不多。
  本来我还以为本题,需要用到双向队列(模拟)呢,不过,没想到这是一道中等题,没考的那么深
  此外,本题你需要重载一下priority_queue;
  好了,说正题
  本题在插入获取数据的时候,会遇到两种情况
  1、一连串相同的,共需用一次魔法
  2、遇到最大的,砍一次,需用一次魔法
  3、还有在遇到1时,直接弹出队列。不需要用到魔法。
  具体实现方式,在下方的😉
*/

#include <bits/stdc++.h>
#define int long long
#define x first
#define y second

using namespace std;

struct cmp{
	bool operator()(const pair<int,int>& p1,const pair<int,int>& p2){
		if(p1.x==p2.x) return p1.y>p2.y; // 小顶堆
		return p1.x<p2.x; // 不改变符号时,默认为大顶堆  
	}	
};

int get_res(int cnt){ // 本题的公式,化简 
	return floor(sqrtl(floor(double(cnt)/2)+1));
}

signed main(){
	priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> pq;
	int n;
	cin>>n;
	for(int i=0; i<n; ++i){
		int num;
		cin>>num;
		pq.emplace(num,i);	
	}
	int cnt=0;
	int temp_id=-2,temp_cnt=-2;
	while(!pq.empty()){ // 优先队列不为空
		auto cur = pq.top();
		pq.pop(); // 直接删除 
		if(cur.x==1) continue;
		if(temp_id==cur.y-1&&temp_cnt==cur.x){
			// 当是下一个相同的值的时候
			temp_id=cur.y; 
			int val = get_res(cur.x); 
			if(val!=1) pq.emplace(val,temp_id);
		}else{
			// 这是一个新的不同的数值
			cnt++;
			temp_cnt=cur.x;
			temp_id =cur.y;
			int val = get_res(cur.x);
			if(val!=1) pq.emplace(val,temp_id);
		}
	} 
	cout<<cnt;
	
	return 0;
} 

知识点

一、double 与 long double

double 
  • 大小:通常占用 8字节(64位)
  • 十进制取值范围:有效位数 约为15~17位
long double
  • 大小:有编译器决定,标准规定不少于double
    但是,在某些编辑器,与double占用的字节(8字节)是相同的
            在GCC编辑器的x86_64架构下,可能占12字节(96位);
            甚至在部分平台占用16字节(128位)(拓展进度)
  • 十进制取值范围:通常比double更大,通常有效位数18-19位

二、揭开 C++ 数学函数后缀的神秘面纱:fl 与精度战争

1、绝对值函数
  • fabs(double x) 计算double类型的绝对值
  • fabsf(float x) 计算float类型的绝对值
  • fabsl(long double x) 计算long double 类型的绝对值
2、取整函数
向上取整
  • ceil(double x) :对double向上取整
  • ceilf(float x):对float向上取整
  • ceill(long double x):对long double向上取整
向下取整

floor(double x)、floor(float x)、floor(long double x)。

四舍五入

round、roundf、roundl

3、开方

sqrt(double x)、sqrtf(float x)、sqrtl(long double x)

4、指数对数函数

三、不用+号的,加法

给出两个整数 a 和 b , 求他们的和并以整数(int)的形式返回。不能使用 + 等数学运算符。

样例

输入:

a = 1
b = 2
输出:

3

其实,这个是根据位运算^(存不进位的结果)与&(存进位的结果)

#include <iostream>
using namespace std;
int main(){
	int a=5;
	int b=3;
	int temp_a,temp_b;
	while(b!=0){
		temp_a = a^b; // 存放 不进位数 
		temp_b = a&b; // 仅存放 进位数 
		temp_b<<=1; // 将 进位的结果 右移 
		a=temp_a;
		b=temp_b; 
	}
	cout<<a;
	return 0;
} 

四、状态压缩动态规划

五、为什么二维 vector 在 C++ 中慢如蜗牛?—— 数组与 vector 的性能对决

1、内存分配方式

vector<vector<int>> 

  • 这是一个二维动态数组,每个内部的vector单独分配内存。内存的分布是非连续的
  • 访问代价大,不同vector之间非连续,内存命中率低,会降低访问速度。

int arr[n][m]

  • 内存是连续的,直接分配一个n*m大小的内存,访问元素时缓存利用率高,性能更优。
  • 查找内存也非常方便,(i,j)--base+i*m+j,无序跳跃式访问。
2、初始化开销

vector<vector<int>> 

  • 在初始化时,需要多次调用构造器,去构造vector。 

int arr[n][m]

  • 全局或静态声明的数组,在程序刚启动时直接就能初始化,无需运行时开销。
3、扩容代价

vector

  • 当容量不够时,会扩容,然后复制拷贝。
  • 内存碎片化增加,影响后续分配效率。

静态数组

  • 大小固定,无扩容问题
4、内存占用

vector中,有各种额外元素(size、capacity、allocator等),占用内存更高。

静态数组,只是存储容量。

六、memset与sizeof

memset

C 库函数 void *memset(void *str, int c, size_t n) 用于将一段内存区域设置为指定的值。

memset() 函数将指定的值 c 复制到 str 所指向的内存区域的前 n 个字节中,这可以用于将内存块清零或设置为特定值。

在一些情况下,需要快速初始化大块内存为零或者特定值,memset() 可以提供高效的实现。

在清空内存区域或者为内存区域赋值时,memset() 是一个常用的工具函数。

重点!!通常memset是对每一个字节赋值,所以分配时,只能分配0 or -1(负一的补码为:1111)。-1用来赋值,0一般是用来清空。

void *memset(void *str, int c, size_t n)
  • str -- 指向要填充的内存区域的指针。
  • c -- 要设置的值,通常是一个无符号字符。
  • n -- 要被设置为该值的字节数。
#include <bits/stdc++.h>
using namespace std;
int main(){
	int arr[2][4];
	cout<<sizeof(arr)<<endl;
	cout<<sizeof(arr[0])<<endl;
	cout<<sizeof(arr[0])/sizeof(arr[0][0])<<endl;
	memset(arr,-1,sizeof(arr));
	cout<<arr[1][1];
	return 0;
} 
--------------------------------
32
16
4
-1
--------------------------------
sizeof

通过上述的例子,应该就能看出,sizeof求的是字节数。


如果更好的建议、请留言,我会 一 一查看。( •̀ ω •́ )✧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2330279.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【EC200N-CN——Linux驱动移植】问题回顾

【EC200N-CN——Linux驱动移植】问题回顾 1&#xff09;、开发回顾一、问题回顾与解决过程二、核心原理分析1. **USB设备识别的关键&#xff1a;VID/PID**2. **为什么之前不生成ttyUSB节点&#xff1f;**3. **为什么添加PID后就能生成节点&#xff1f;** 三、日志关键信息解读1…

构建k8s下Helm私有仓库与自定义Chart开发指南

#作者&#xff1a;程宏斌 文章目录 自定义helm模板1、开发自己的chare包2、调试chart3、安装chart 自定义helm模板 https://hub.helm.sh/ 1、开发自己的chare包 [rootmaster ~]# helm create mychare //创建一个名为mychare的chare包 [rootmaster ~]# tree -C mychare/ //以…

【7】C#上位机---Modbus RTU 界面设计与封装

C#上位机---Modbus通讯 1 Modbus RTU 通讯1.1 RS485串口与串行通信(Serial Communications)1.2 Modbus RTU协议1.3 Modbus RTU主从模式1.4 Modbus 主从站模拟调试2 Modbus RTU 界面设计与封装2.1 温度控件的类属性2.2 C#封装Modbus实现通讯2.3 C#封装Modbus TRU通用类2.4 上位…

【嵌入式学习6】多任务版TCP服务器

目录 如何实现&#xff1a; 客户端1.0版本&#xff1a; 服务端&#xff1a; 客户端2.0版本&#xff1a; thread.join() 是一个线程同步方法&#xff0c;用于主线程等待子线程完成。当你调用 thread.join() 时&#xff0c;主线程会阻塞&#xff0c;直到调用 join() 的子线程…

每天认识一个设计模式-外观模式:化繁为简的接口魔法

一、前言 在设计模式中&#xff0c;结构型设计模式处理类或对象组合&#xff0c;可助力构建灵活、可维护软件结构。此前探讨过组合模式&#xff08;将对象组合成树形结构&#xff0c;统一处理单个与组合对象&#xff0c;如文件系统管理&#xff09;和装饰器模式&#xff08;动…

VLAN(虚拟局域网)

一、vlan概述 VLAN(virtual local area network)是一种通过逻辑方式划分网络的技术&#xff0c;允许将一个物理网络划分为多个独立的虚拟网络。每一个vlan是一个广播域&#xff0c;不同vlan之间的通信需要通过路由器或三层交换机 [!注意] vlan是交换机独有的技术&#xff0c;P…

Transformers without Normalization论文翻译

论文信息&#xff1a; 作者&#xff1a;Jiachen Zhu, Xinlei Chen, Kaiming He, Yann LeCun, Zhuang Liu 论文地址&#xff1a;arxiv.org/pdf/2503.10622 代码仓库&#xff1a;jiachenzhu/DyT: Code release for DynamicTanh (DyT) 摘要 归一化层在现代神经网络中无处不在…

题目练习之set的奇妙使用

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…

网站提示“不安全“怎么办?原因分析与解决方法

引言&#xff1a;为什么浏览器会提示网站"不安全"&#xff1f; 当您访问某些网站时&#xff0c;浏览器可能会显示"不安全"警告。这通常意味着该网站存在安全风险&#xff0c;可能影响您的隐私或数据安全。本文将介绍常见原因及解决方法&#xff0c;帮助您…

如何利用AI智能生成PPT,提升工作效率与创意表现

如何利用AI智能生成PPT&#xff0c;提升工作效率与创意表现&#xff01;在这个信息爆炸的时代&#xff0c;制作一份既专业又富有创意的PPT&#xff0c;已经不再是一个简单的任务。尤其是对于每天都需要做报告、做展示的职场人士来说&#xff0c;PPT的质量直接影响着工作效率和个…

【数据结构】图论存储革新:十字链表双链设计高效解决有向图入度查询难题

十字链表 导读一、邻接表的优缺点二、十字链表2.1 结点结构2.2 原理解释2.2.1 顶点表2.2.2 边结点2.2.3 十字链表 三、存储结构四、算法评价4.1 时间复杂度4.2 空间复杂度 五、优势与劣势5.1 优势5.2 劣势5.3 特点 结语 导读 大家好&#xff0c;很高兴又和大家见面啦&#xff…

.net6 中实现邮件发送

一、开启邮箱服务 先要开启邮箱的 SMTP 服务&#xff0c;获取授权码&#xff0c;在实现代码发送邮件中充当邮箱密码用。 在邮箱的 设置 > 账号 > POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务中&#xff0c;把 SMTP 服务开启&#xff0c;获取授权码。 二、安装库 安装 …

【Linux】命令和权限

目录&#xff1a; 一、shell命令及运行原理 &#xff08;一&#xff09;什么是外壳 &#xff08;二&#xff09;为什么要有外壳 &#xff08;三&#xff09;外壳怎么工作的 二、Linux权限的概念 &#xff08;一&#xff09;Linux的文件类型 &#xff08;二&#xff09;L…

22.OpenCV轮廓匹配原理介绍与使用

OpenCV轮廓匹配原理介绍与使用 1. 轮廓匹配的基本概念 轮廓匹配&#xff08;Contour Matching&#xff09;是计算机视觉中的一种重要方法&#xff0c;主要用于比较两个轮廓的相似性。它广泛应用于目标识别、形状分析、手势识别等领域。 在 OpenCV 中&#xff0c;轮廓匹配主要…

深入解析AI绘画技术背后的人工智能

在当今数字艺术领域&#xff0c;AI绘画作为一种新兴艺术形式&#xff0c;正迅速吸引着越来越多的创作者与爱好者。它不仅推动了艺术创作的边界&#xff0c;同时也改变了我们对创作与美的理解。本文将深入探讨AI绘画所依赖的人工智能技术&#xff0c;并分析其背后的原理与应用。…

browser-use开源程序使 AI 代理可以访问网站,自动完成特定的指定任务,告诉您的计算机该做什么,它就会完成它。

一、软件介绍 文末提供程序和源码下载 browser-use开源程序使 AI 代理可以访问网站&#xff0c;自动完成特定的指定任务&#xff0c;浏览器使用是将AI代理与浏览器连接的最简单方法。告诉您的计算机该做什么&#xff0c;它就会完成它。 二、快速开始 使用 pip &#xff08;Py…

java虚拟机---JVM

JVM JVM&#xff0c;也就是 Java 虚拟机&#xff0c;它最主要的作用就是对编译后的 Java 字节码文件逐行解释&#xff0c;翻译成机器码指令&#xff0c;并交给对应的操作系统去执行。 JVM 的其他特性有&#xff1a; JVM 可以自动管理内存&#xff0c;通过垃圾回收器回收不再…

2025数字中国初赛wp

一&#xff0c;取证与溯源 镜像文件解压密码&#xff1a;44216bed0e6960fa 1.运维人员误删除了一个重要的word文件&#xff0c;请通过数据恢复手段恢复该文件&#xff0c;文件内容即为答案。 先用R-stuido软件进行数据恢复 得到 打开重要文件.docx全选发现有一条空白的被选中…

c#和c++脚本解释器科学运算

说明&#xff1a; 我希望用c#和c写一个脚本解释器&#xff0c;用于科学运算 效果图&#xff1a; step1: c# C:\Users\wangrusheng\RiderProjects\WinFormsApp3\WinFormsApp3\Form1.cs using System; using System.Collections.Generic; using System.Data; using System.Tex…

青蛙吃虫--dp

1.dp数组有关元素--路长和次数 2.递推公式 3.遍历顺序--最终影响的是路长&#xff0c;在外面 其次次数遍历&#xff0c;即这次路长所有情况都更新 最后&#xff0c;遍历次数自然就要遍历跳长 4.max时时更新 dp版本 #include<bits/stdc.h> using namespace std; #def…