第十四届蓝桥杯省赛C++B组题解

考点

暴力枚举,搜索,数学,二分,前缀和,简单DP,优先队列,链表,LCA,树上差分

A 日期统计

暴力枚举:

#include<bits/stdc++.h>
using namespace std;
int b[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int a[50];
int h,m,s;
set<int>q;//用来排重
int main()
{  
    for(int i=1;i<=40;i++)//年份已固定,只用从后40位枚举
    {
        cin>>a[i];
    }
    for(int i=1;i<=40;i++)
        for(int j=i+1;j<=40;j++)
         for(int k=j+1;k<=40;k++)
             for(int p=k+1;p<=40;p++)
             {
                 h=a[i]*1000+a[j]*100+a[k]*10+a[p];
                 m=a[i]*10+a[j];
                 s=a[k]*10+a[p];
                 if(m>0&&m<=12&&s>0&&s<=b[m])
                     q.insert(h);
             }
    cout<<q.size()<<endl;
}

B 01串的熵

暴力枚举:

#include <iostream>
#include <cmath>
using namespace std;
int main()
{
    int n = 23333333;
    for (int i = 1; i < n; ++i)
    {
        double a = i * 1.0 / n;  // 0出现的占比
        double b = (n - i) * 1.0 / n;  // 1出现的占比
        double res = 0;
        res -= a * log2(a) * i + b * log2(b) * (n - i);
        if (fabs(res - 11625907.5798) < 0.0001)
        {
            cout << i << endl;
            break;
        } 
    }
    return 0;
}

C 冶炼金属

解题思路:
最大值可以遍历比较得出,但是最小值要么使用数学公式,要么就是二分答案

公式法:

#include <iostream>
using namespace std;
typedef long long ll;
ll N,A[10010],B[10010],res[10010],res2[10010];
ll minres=1e9+7;
ll maxres2=-1;
int main()
{
  cin>>N;

  for(int i=0;i<N;i++){
      cin>>A[i]>>B[i];
      res[i]=A[i]/B[i];
      minres=min(minres,res[i]);
      res2[i]=A[i]/(B[i]+1);
      maxres2=max(maxres2,res2[i]);
  }
  
  cout<<maxres2+1<<" "<<minres;
  return 0;
}

二分答案:

#include<bits/stdc++.h>
using namespace std;
int a[200100],b[200100],n;
int find(int x){
	for(int i=1;i<=n;i++){
		if(a[i]/x>b[i]){
			return 1;
		}else if(a[i]/x<b[i]){
			return 0;
		}
	}
	return 0;
}
int main(){
	int minn=INT_MAX,maxx=INT_MAX;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i]>>b[i];
		maxx=min(maxx,a[i]/b[i]);
	}
	int l=0,r=1e9,mid=0;
	while(l<=r){
		mid=(l+r)/2;
		if(find(mid)){
			l=mid+1;
		}else{
			r=mid-1;
		}
	}
	cout<<l<<" "<<maxx<<endl;
	return 0;
}

D 飞机降落

题目大意:
给你n架飞机的到达,降落花费和可等待时间,让你求是否能全部安全降落

解题思路:
因为最大数据为10,直接上dfs,遍历所有情况,是否有可以降落的情况,注意一下回溯和边界处理就行。(多实例,记得将标记数组初始化)

#include<bits/stdc++.h>
using namespace std;
#define int long long 
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define endl "\n";
int t[20],d[20],l[20],vis[20];
int n,flag; 
void dfs(int sum,int ans){
	if(ans>=n){
		flag=1;
		return ;
	}
	for(int i=1;i<=n;i++){
		if(!vis[i]&&(sum<=t[i]||sum<=t[i]+d[i])){
			if(sum<=t[i]){
				vis[i]=1;
				dfs(t[i]+l[i],ans+1);
			}else if(sum<=t[i]+d[i]){
				vis[i]=1;
				dfs(sum+l[i],ans+1);
			}else{
				continue;
			}
			vis[i]=0;
		}
	}
} 
void solve(){
	memset(vis,0,sizeof(vis));
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>t[i]>>d[i]>>l[i];
	}
	flag=0;
	dfs(0,0);
	if(flag){
		cout<<"YES"<<endl;
	}else{
		cout<<"NO"<<endl;
	}
	return ;
}
signed main()
{
	IOS
	int t=1;
	cin>>t;
	while(t--)
	solve();
    return 0;
}

E 接龙数列

题目大意:

给你n个数,问你删除几个可以将剩下的组成接龙数列。

解题思路:
因为接龙数列只需要判断首个数字和末尾数字,而且只能有 0 − 9 0-9 09十种可能,所以,只需要开一个dp数组,将每个数的首个数字和末尾数字进行存储,并更新以末尾数字结尾的数组,即是否小于当前以首个数字结尾的接龙数列的长度+1的长度,小于则更新,最后输出最长的一个接龙数列的长度即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long 
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define endl "\n";
int dp[20];
void solve(){
	int n,maxx=0,a,b;
	string x;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>x;
		a=x[0]-'0';
		b=x[x.size()-1]-'0';
		dp[b]=max(dp[b],dp[a]+1);
		maxx=max(dp[b],maxx);
	}
	cout<<n-maxx<<endl;
	return ;
}
signed main()
{
	IOS
	int t=1;
	//cin>>t;
	while(t--)
	solve();
    return 0;
}

F 岛屿个数

题目大意:
给你一个n*m的矩阵,由海0和陆地1组成,一个1围成的还就是一个岛屿,但是岛屿里面的岛屿属于子岛屿,不属于岛屿的范畴,让你求一共由多少个岛屿。

解题思路:
因为有环中环的情况,而且只需要判断最外环的情况,所以从最外围的海水开始遍历,接触到最外围海水的一定是岛屿,然后就先dfs一遍把最外围海水标记了,再从外围海水向陆地dfs一遍,每次遍历岛屿数量都加一,最后得出结果。

#include <stdio.h>
#include <stdlib.h>

int M, N, d[52][52];

void dfs_sea(int i, int j)
{
    if ((i >= 0 && i <= M + 1) && (j >= 0 && j <= N + 1))
    {
        if (d[i][j] == 0)
        {
            d[i][j] = 2;//标记出外海
            //八个方向 
            dfs_sea(i, j + 1);
            dfs_sea(i, j - 1);
            dfs_sea(i + 1, j);
            dfs_sea(i + 1, j + 1);
            dfs_sea(i + 1, j - 1);
            dfs_sea(i - 1, j);
            dfs_sea(i - 1, j + 1);
            dfs_sea(i - 1, j - 1);
        }
    }
}

void dfs_island(int i, int j)
{
    if ((i >= 0 && i <= M + 1) && (j >= 0 && j <= N + 1))
    {
        if (d[i][j] == 1)
        {
            d[i][j] = 3;//搜索过的岛屿不再搜索 
            dfs_island(i + 1, j);//右 
            dfs_island(i - 1, j);//左 
            dfs_island(i, j + 1);//上 
            dfs_island(i, j - 1);//下 
        }
    }
}

int main(int argc, char *argv[])
{
    // 请在此输入您的代码
    int T;
    scanf("%d", &T);
    while (T--)
    {
        scanf("%d %d", &M, &N);
        //填充海水
        for (int i = 0; i < N + 2; i++)
        {
            d[0][i] = 0;
            d[M + 1][i] = 0;
        }
        for (int i = 1; i < M + 1; i++)
        {
            d[i][0] = 0;
            d[i][N + 1] = 0;
        }
        //输入图 
        for (int i = 1; i < M + 1; i++)
        {
            for (int j = 1; j < N + 1; j++)
            {
                scanf("%1d", &d[i][j]);
            }
        }

        dfs_sea(0, 0); //找出所有外海 

        int count;//计算岛屿数量 
        count = 0;
        for (int i = 0; i < M + 2; i++)
        {
            for (int j = 0; j < N + 2; j++)
            {
                if (d[i][j] == 1 && d[i - 1][j] == 2)//只能从外海搜索岛屿,所以岛屿前一定是外海“2”
                {
                    dfs_island(i, j);//搜索岛屿 
                    count++;
                }
            }
        }
        printf("%d\n", count);
    //以下代码可以打印出处理后的图
        /*for (int i = 0; i < M + 2; i++)
        {
            for (int j = 0; j < N + 2; j++)
            {
                printf("%1d", d[i][j]);
                if (j == N + 1)
                printf("\n");
            }
        }*/
    }
    return 0;
}

G 子串简写

题目大意:给定一个字符串和一个长度K,再给出两个字符a和b,求字符串有多少个长度大于等于K且是以a为首字母,b为尾字母的子串。

解题思路:
因为只需要判断首尾,所以可以直接从字符串的尾部向前遍历并用前缀和来记录b字符的个数,最后字符串从前往后遍历,每遇到一个a字符,就判断在其k-1的长度后,有多少个b字符,将其数量累加,最后输出即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long 
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define endl "\n";
int sum[1000100];
void solve(){
	int n,num=0;
	string x;
	char aa,bb;
	cin>>n;
	cin>>x;
	cin>>aa>>bb;
	for(int i=x.size()-1;i>=0;i--){
		if(x[i]==bb){
			sum[i]+=sum[i+1]+1;
		}else{
			sum[i]+=sum[i+1];
		}
	}
	for(int i=0;i<x.size();i++){
		if(x[i]==aa){
			num+=sum[i+n-1];
		}
	}
	cout<<num<<endl;
	return ;
}
signed main()
{
	IOS
	int t=1;
	//cin>>t;
	while(t--)
	solve();
    return 0;
}

H 整数删除

题目大意:给你n个数,和k次操作,每次操作将当前剩余数中最小数的左右两个数加上当前最小数的值(多个最小数从前往后进行操作,左边或者右边没有数则不操作),并将这个最小数剔除,问你k次操作后的序列是什么。

解题思路:
因为需要动态维护最小值,所以使用优先队列,但是因为每次进行操作后,最小值可能会发生变化,所以需要加上双向链表进行优化。

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

const int N = 5e5 + 10;
ll v[N], l[N], r[N];

void del(int x) {
    r[l[x]] = r[x], l[r[x]] = l[x];
    v[l[x]] += v[x], v[r[x]] += v[x];
}

int main () {
    int n, k; cin >> n >> k;
    r[0] = 1, l[n + 1] = n;
    priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<pair<ll, int>>> h;
    for (int i = 1; i <= n; i ++)
        cin >> v[i], l[i] = i - 1, r[i] = i + 1, h.push({v[i], i});
    while (k --) {
        auto p = h.top(); h.pop();
        if (p.first != v[p.second]) h.push({v[p.second], p.second}), k ++;
        else del(p.second);
    }
    int head = r[0];
    while (head != n + 1) {
        cout << v[head]<< " ";
        head = r[head];
    }
    return 0;
}

最后两题考到了LCA算法,有点属于盲区了算是,回去恶补一下,两周内题解补上!!!

  • 56
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蓝桥杯是一个国内著名的计算机比赛,为了帮助参赛者更好地准备和了解比赛的题型,委会会公布历年的真题并提供相应的题解。 首先,我们需要了解蓝桥杯是一个综合性的计算机比赛,测试的对象包括计算机基础知识、编程能力以及解决实际问题的能力。 在历年的真题中,参赛者将面临不同类型的题目,包括算法设计与优化问题、数据结构算法问题、编程题等。其中针对Python B的题目主要考察的是对Python语言的掌握和应用能力。 题目解答一般会包含以下几个方面的内容: 1. 题目分析与理解:读取题目,理解题目的要求和限制条件。通过仔细分析题目,确定题目的输入与输出,以及问题的核心。 2. 设计解决方案:根据题目要求和限制条件,设计一个合适的解决方案。可以使用合适的算法数据结构来解决问题,并做出相应的性能优化。 3. 编写代码实现:根据设计的方案编写相应的代码实现。需要注意的是,Python语言有其独特的语法和特性,掌握好这些特性可以更好地完成编程任务。 4. 调试与测试:编写完代码后,需要进行调试和测试。通过运行样例输入和输出,检查代码是否符合题目要求,并且没有逻辑上的错误。 5. 总结与优化:在完成题目解答后,可以进行总结和优化。包括分析算法复杂度、代码风格和可读性等方面,以便在比赛中更好地表现。 在准备蓝桥杯时,可以通过阅读历年的真题和题解来了解比赛的难度和类型,针对性地进行练习和提高。同时也可以参加相关的培训班和讨论活动,与其他参赛者交流经验和技巧。 总而言之,历年蓝桥杯真题的解答对于提高自己的编程能力和应对比赛非常有帮助。通过认真分析和实践,可以更好地理解并掌握Python编程,并在比赛中取得更好的成绩。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值