第十四届蓝桥杯B组C/C++真题小结

1.日期统计

分析:100个数字可以存在一个静态数组中,对于统计的日期,另外再用一个数组存储。而不知道具体数组的大小,就没办法初始化,所以使用一个动态数组存储,比如STL库中的set容器,因为题目要求相同的日期只需要统计一次,set容器的特点就是可以避免相同的键值,使用这个容器的优势还在于方便的进行数据的插入和长度的计算,可以很好的用来解题。再者它是一个八位日期的数字,前四位相同,所以只需要存储后四位数字即可,利用八重循环,找出合法日期。注意在月份和天数处理时,判断其合法性,由于2023不能被4整除也不能被100整除,所以是平年。2月只有28天,以月份作为天数的判断条件。对于月份或者天数的长度只有一位时,题目要求补充前导零。可以这么来处理,把它当作一个四位数来看。月份的前导零可以不用添加,当月份只有一位数时乘以100直接加上天数,这样天数只有一位时,前导零便有了。

源代码:

#include <bits/stdc++.h>
using namespace std;
int num[110];
int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

int main() {
    for (int i=0;i<100;i++)  cin >>num[i];  //输入100个数
    set<int> ans;
    for (int i = 0; i < 100; i++)
        for (int j = i + 1; j < 100; j++)
            for (int k = j + 1; k < 100; k++)
                for (int v = k + 1; v < 100; v++) //前4个数字构成年
                {
                    int y = num[i] * 1000 + num[j] * 100 + num[k] * 10 + num[v];   //年

                    if (y == 2023) {                       //找到了年,再找月、日
                        for (int m = v + 1; m < 100; m++)
                            for (int n = m + 1; n < 100; n++)
                                for (int o = n + 1; o < 100; o++)
                                    for (int p = o + 1; p < 100; p++)
                                    {
                                        int mon = num[m] * 10 + num[n];   //月
                                        int d = num[o] * 10 + num[p];     //日

                                        if ((mon >= 1 && mon <= 12) && (d >= 1 && d <= days[mon]))
                                        {
                                            int temp = mon * 100 + d;
                                            ans.insert(temp);      //用set去重
                                        }
                                    }
                        break;
                    }
                }
    cout << ans.size();

    return 0;
}

蓝桥杯题库跳转

2.01串的熵

分析:这个题目也是纯暴力,可以通过枚举解题。假如有x个1,那么就有23333333-x个0,直接根据公式计算信息熵,写一个函数,因为c++有log2()函数,所以可以直接拿来用。把计算出来的信息熵与题目给的数字求差的绝对值,精度精确到1e-4方即可。因为题目要求0的次数比1少,所以对于输出的两个数中,取较小的数。

源代码:

#include<bits/stdc++.h>
using namespace std;
double hs(int a,int b){
	double x1=1.0*a/(a+b);
	double x2=1.0*b/(a+b);
	double ans=-a*x1*log2(x1)-b*x2*log2(x2);
	return ans;
}
int main(){
	for(int i=0;i<=23333333;i++){
		if(fabs(hs(i,23333333-i)-11625907.5798)<0.0001){
          cout<<i<<endl;
          break;
        }		
	} 
	return 0;
} 

 蓝桥杯题库跳转

3.冶炼金属

分析:75/3=25 53/2=26 59/2=29 Vmax取最小 75/(3+1)=18 53/(2+1)=17 59/(2+1)=19 Vmin等于最大值加1,因为边界取不到,所以最小值取最大数加1.

源代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
  int Vmax=999999999,Vmin=0,n;
  cin>>n;
  for(int i=1;i<=n;i++){
    int x1,x2;
    cin>>x1>>x2;
    int t1=x1/(x2+1)+1;
    if(t1>Vmin)
      Vmin=t1;//更新最小值
    int t2=x1/x2;
    if(t2<Vmax)
      Vmax=t2;//更新最小值
  }
  cout<<Vmin<<" "<<Vmax;
  return 0;
}

蓝桥杯题库跳转

4.飞机降落

分析:对于该题可以采用dfs算法,当前飞机的状态,开始降落的时间T加上盘旋的的时间D要大于等于上一架飞机的最早降落时间time,否则飞机相撞。反之可以降落,更新飞机的最早降落时间max(T,time)+L,全部降落成功则输出YES,在降落过程中可能有多种方案,只要有一种状态成功即可,这里可以剪枝。反之只要有一架飞机不能成功降落,则需要进行回溯,穷举所有情况,如果都不能成功降落,则输出NO。

#include<bits/stdc++.h>
using namespace std;
const int Max_N=11;
bool have_answer,use[Max_N];//use[Max_N]表示尝试降落的飞机 
int T,N,t[Max_N],d[Max_N],l[Max_N];
void dfs(int x,int time){
	if(have_answer)return;
	if(x==N){//全部降落成功 
		have_answer=1;
		return;
	}
	for(int i=1;i<=N;i++){
		if(!use[i]&&time<=t[i]+d[i]){//降落时间比最晚时间要早,就可以尝试去降落 
			use[i]=1;
			dfs(x+1,max(t[i],time)+l[i]);//更新降落时间
			if(have_answer)return;
			use[i]=0; 
		} 
	} 
}
int main(){
	cin>>T;
	while(T--){
		cin>>N;
		have_answer=0;
		for(int i=1;i<=N;i++){
			cin>>t[i]>>d[i]>>l[i];
			use[i]=0;
		}
		dfs(0,0);	
		if(have_answer)cout<<"YES\n";
		else cout<<"NO\n";
	}
	return 0;
} 

蓝桥杯题库跳转

5.接龙序列

分析:求最少的删除个数,也就是求解出数列中最长的接龙数列,计算出最长的接龙数列长度,数列总长度-最长接龙数列长度等于最少删除次数。可以尝试用动态规划来解,状态为当前最长接龙数列长度,则dp[i]就是以i为数字最后一位的最长接龙数列长度,设x为当前数字的第一位(如果为接龙数列,也就是前一位数的最后一位),y为当前数字的最后一位,则状态转移方程可以写为dp[y]=max(d[x]+1,dp[y])。

源代码:

#include <bits/stdc++.h>
using namespace std;
int dp[10];//必须声明为全局变量
int main()
{
  int N;
  cin>>N;
  string s;
  int m=0;
  for(int i=0;i<N;i++){
    cin>>s;
    int x=s[0]-'0',y=s[s.size()-1]-'0';
    dp[y]=max(dp[x]+1,dp[y]);//状态转移方程
    m=max(m,dp[y]);
  }
  cout<<N-m<<endl;
  return 0;
}

蓝桥杯题库跳转

6.岛屿个数

#include<bits/stdc++.h>
using namespace std;
const int MAX_N=51;
int M,N;
string mp[MAX_N];
bool vis[MAX_N][MAX_N],used[MAX_N][MAX_N];
//八个方向 下 上 右 左 右下 左下 右上 左上 
int dx[]={0,0,1,-1,1,-1,1,-1};
int dy[]={1,-1,0,0,1,1,-1,-1}; 
bool bfs_out(int x,int y){
	//为避免走重复的路 需要新建一个数组来标记走的路 每次使用都要清空 
	for(int i=0;i<M;i++){
		for(int j=0;j<N;j++)
			used[i][j]=0; 
	}
	queue<int>qx,qy;
	qx.push(x);qy.push(y);used[x][y]=1;
	while(!qx.empty()){
		x=qx.front();qx.pop();
		y=qy.front();qy.pop();
		//如果走到边界 那么它就是一个单独的岛屿 
		if(x==0||x==M-1||y==0||y==N-1) return true;
		for(int i=0;i<8;i++){
			int nx=x+dx[i];
			int ny=y+dy[i];
			//如果岛屿出界 或者路线已经走过了 或者是陆地 那么就不要 
			if(nx<0||ny<0||nx>=M||ny>=N||used[nx][ny]||mp[nx][ny]=='1')continue;
			//把该路线连接起来 
			qx.push(nx);qy.push(ny); 
			used[nx][ny]=1; 
		}
	} 
	//没逃出去 
	return false; 
} 
void bfs_col(int x,int y){
	queue<int>qx,qy;
	//标记岛屿 
	qx.push(x);qy.push(y);vis[x][y]=1;
	while(!qx.empty()){
		x=qx.front();qx.pop();
		y=qy.front();qy.pop();
		for(int i=0;i<4;i++){
			int nx=x+dx[i];
			int ny=y+dy[i];
			//如果岛屿出界 或者被访问过 或者是海水 那么就不要 
			if(nx<0||ny<0||nx>=M||ny>=N||vis[nx][ny]||mp[nx][ny]=='0')continue;
			//把该岛屿连接起来 
			qx.push(nx);qy.push(ny); 
			vis[nx][ny]=1; 
		}
	}
} 
void solve(){
	cin>>M>>N;
	for(int i=0;i<M;i++){
		cin>>mp[i];
		for(int j=0;j<N;j++)
			vis[i][j]=0;
	}
	int ans=0;
	for(int i=0;i<M;++i)
		for(int j=0;j<N;j++)
			//如果这个点没被标记过并且是一个岛屿 
			if(!vis[i][j]&&mp[i][j]=='1'){
				//那么进行染色 
				bfs_col(i,j);
				//判断岛屿能否逃出去 可以 就计入岛屿总数中 反之 不能逃出去 那就是子岛屿 不用管 
				if(bfs_out(i,j))++ans;
			}
	cout<<ans<<'\n'; 
}
int main(){
	ios::sync_with_stdio(0);cin.tie(0);
	int T;cin>>T;
	while(T--) solve(); 
	return 0;
} 

分析:题目核心在于 判断一个岛屿是不是子岛屿,取决于这个岛屿是否被围住了。如果这个岛屿能够“逃到”地图的边界,那么它就不是一个子岛屿,就是一个单独的岛屿,需要统计。岛屿出现时,标记相邻的岛屿(上,下,左,右),表示同属于一个岛屿,检查某个岛屿能否从边界逃出去,去走海水,如果能连接到边界的海水,那么它就不是一个子岛屿,就需要统计,注意逃的时候,是上,下,左,右,左上,左下,右上,右下八个方向。

蓝桥杯题库跳转

7.子串简写

分析:可以利用前缀和的思想,先收集所有以c1开头的字符,每一次收集时,判断相隔k-1个字符的结尾字符是否以c2结尾,如果是,那么将之前遇到的c1全部累加,可以想象成一个滑条,从最开始的c1滑到当前符合条件的c2,循环一轮即得出结果。

#include <bits/stdc++.h>
using namespace std;
int k;
char c1,c2;
string s;
int main()
{
  cin>>k>>s>>c1>>c2;
  long long ans=0;
  int q_z_h=0;
  //保持字串的第一个字符与最后一个字符的长度至少为k
  for(int j=k-1,i=0;i<s.size();i++,j++){
    //出现以c1开始的子串 找到符合条件的c1并累加
    if(s[i]==c1) q_z_h++;
    //出现以c2结束的子串 如果符合条件 那么将之前的c1都累加求和 最后得出结果
    if(s[j]==c2) ans+=q_z_h; 
  }
  cout<<ans;
  return 0;
}

蓝桥杯题库跳转

8.整数删除

#include <bits/stdc++.h>
using namespace std;
map<int,int>p;
bool comp(const pair<int,int>left,const pair<int,int>right){
  return left.second<right.second;
}
int main()
{
  ios::sync_with_stdio(0),cin.tie(0);
  int N,K;
  cin>>N>>K;
  for(int i=0;i<N;i++){
    cin>>p[i];//以i为键 键盘读入的数为值
  }
  //定义迭代器指针
  map<int,int>::iterator it;
  while(K--){//开始删除
    //在it容器中找到second成员最小的pair<int, int>元素,并将指向该元素的迭代器存储在it(迭代器)中。
    //把it想象成一个引用变量 从p中取值
    it=min_element(p.begin(),p.end(),comp);
    int A=it->second;//获取最小值
    if(it!=p.begin()){//it不是第一个值
      it--;
      //it为迭代器 存储两个数值 不能直接与int A相加
      it->second+=A;
      it++;
    }
    if(it!=p.end()){//it不是最后一个值
      it++;
      it->second+=A;
      it--;
    }
    //删除最小值 
    p.erase(it);
  }
  for(it=p.begin();it!=p.end();it++)
    cout<<it->second<<" ";
  return 0;
}

30%通过

#include<bits/stdc++.h>
using namespace std;
#define val first
#define pos second
typedef long long LL;
typedef pair<LL,int>PLI;
const int MAX_N=5e5+5;
int N,K,pre[MAX_N],nxt[MAX_N];
LL A[MAX_N];
priority_queue<PLI>q;
int main(){
	ios::sync_with_stdio(0);cin.tie(0);
	cin>>N>>K;
	for(int i=1;i<=N;i++){
		cin>>A[i];
		pre[i]=i-1;
		nxt[i]=i+1;
		q.push({-A[i],-i});
	}
	pre[1]=-1;
	nxt[N]=-1;
	while(K--){
		PLI now;
		do{
			now=q.top();q.pop();
			now.val=-now.val;now.pos=-now.pos;
		}while(A[now.pos]!=now.val);
		int PRE=pre[now.pos];
		int NXT=nxt[now.pos];
		if(PRE!=-1){
			A[PRE]+=now.val;
			q.push({-A[PRE],-PRE});
			nxt[PRE]=NXT; 
		}
		if(NXT!=-1){
			A[NXT]+=now.val;
			q.push({-A[NXT],-NXT});
			pre[NXT]=PRE;
		}
		A[now.pos]=-1;
	}
	for(int i=1;i<=N;++i)
		if(A[i]!=-1)
			cout<<A[i]<<' ';
	return 0;
}

蓝桥杯题库链接

9.景区导游

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAX_N=1e5+1;
vector<int>E[MAX_N],W[MAX_N];
int N,K,dep[MAX_N],fa[MAX_N][21],A[MAX_N];
LL dis[MAX_N]; 
void dfs(int u,int Fa){
	dep[u]=dep[Fa]+1;
	fa[u][0]=Fa;
	for(int i=1;i<=20;++i)
		fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int i=0;i<E[u].size();++i){
		int v=E[u][i],w=W[u][i];
		if(v==Fa) continue;
		dis[v]=dis[u]+w;
		dfs(v,u);
	}
}
int LCA(int u,int v){
	if(dep[u]<dep[v]) swap(u,v);
	for(int i=20;i>=0;--i)
		if(dep[fa[u][i]]>=dep[v])
			u=fa[u][i];
	if(u==v) return u;
	for(int i=20;i>=0;--i)
		if(fa[u][i]!=fa[v][i]){
			u=fa[u][i];
			v=fa[v][i];
		}
	return fa[u][0];
}
LL path_dis(int u,int v){
	if(!u || !v) return 0;
	return dis[u]+dis[v]-2*dis[LCA(u,v)];
}
int main(){
	ios::sync_with_stdio(0); cin.tie(0);
	cin>>N>>K;
	for(int i=1;i<N;++i){
		int u,v,t; cin>>u>>v>>t;
		E[u].push_back(v);
		W[u].push_back(t);
		E[v].push_back(u);
		W[v].push_back(t);
	}
	dfs(1,0);
	LL ans=0;
	for(int i=1;i<=K;++i){
		cin>>A[i];
		ans+=path_dis(A[i],A[i-1]);
	}
	for(int i=1;i<=K;++i)
		cout<<ans-path_dis(A[i-1],A[i])-path_dis(A[i],A[i+1])+path_dis(A[i-1],A[i+1])<<' ';
	return 0;
}

蓝桥杯题库链接

10.砍树

#include "bits/stdc++.h"
using namespace std;
using ll = long long;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int n,m;
    cin >> n >> m;
    vector<vector<pair<int,int>>> edge(n + 1);
    for(int i = 1;i < n;i ++) {
        int x,y;
        cin >> x >> y;
        edge[x].push_back({y,i});
        edge[y].push_back({x,i});
    }
    vector<vector<int>> f(n + 1,vector<int>(19,0));
    vector<int> dep(n + 1),d(n + 1);
    function<void(int,int)> dfs = [&](int x,int fa) {
        f[x][0] = fa;
        dep[x] = dep[fa] + 1;
        for(int i = 1;i <= 18;i ++) {
            f[x][i] = f[f[x][i - 1]][i - 1];
        }
        for(auto [v,id]: edge[x]) {
            if(v != fa) {
                dfs(v,x);
            }
        }
    };
    auto LCA = [&](int x,int y) -> int {
        if(dep[x] < dep[y]) swap(x,y);
        int d = dep[x] - dep[y];
        for(int i = 18;i >= 0;i --) {
            if(d >> i & 1) x = f[x][i];
        }
        if(x == y) return x;
        for(int i = 18;i >= 0;i --) {
            if(f[x][i] != f[y][i]) {
                x = f[x][i];
                y = f[y][i];
            }
        }
        return f[x][0];
    };
    int ans = -1;
    function<void(int,int)> get = [&](int u,int fa) {
        for(auto [v,id]: edge[u]) {
            if(v != fa) {
                get(v,u);
                d[u] += d[v];
            }
        }
        for(auto [v,id]: edge[u]) {
            if(d[u] == m && d[v] == m) {
                ans = max(ans,id);
            }
        }
    };
    dfs(1,0);
    for(int i = 1;i <= m;i ++) {
        int x,y;
        cin >> x >> y;
        int lca = LCA(x,y);
        d[x] ++,d[y] ++;
        d[lca] --,d[f[lca][0]] --;
    }
    get(1,0);
    cout << ans;
    return 0;
}

 蓝桥杯题库链接

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值