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


    考点

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

    A 日期统计

    暴力枚举

    #include
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    B 01串的熵

    暴力枚举:

    #include 
    #include 
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    C 冶炼金属

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

    公式法:

    #include 
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    二分答案:

    #include
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    D 飞机降落

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

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

    #include
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    E 接龙数列

    题目大意:

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

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

    #include
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    F 岛屿个数

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

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

    #include 
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97

    G 子串简写

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

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

    #include
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    H 整数删除

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

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

    #include 
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

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

  • 相关阅读:
    zephyr的启动流程
    linux安装aerospike免安装版
    vmware安装了centos7之后网络设置
    【华为OD机试python】比赛【2023 B卷|100分】
    Code Llama:Llama 2 学会写代码了!
    SpringMVC的工作流程及入门
    Springboot服装服装销售管理系统毕业设计-附源码221801
    【KVM虚拟化】· 虚拟机的冷迁移和热迁移
    windows逆向的工具 (没有Android工具)
    codeforces (C++ Morning)
  • 原文地址:https://blog.csdn.net/weixin_74088105/article/details/136822486