• 2019年第十届蓝桥杯 C / C ++省赛 B 组真题题解


    A: 组队
    在这里插入图片描述
    输入数据

    编号 号位1 2 3 4 5
    
    1 	97 90 0 0 0
    2 	92 85 96 0 0
    3 	0 0 0 0 93
    4 	0 0 0 80 86
    5 	89 83 97 0 0
    6 	82 86 0 0 0
    7 	0 0 0 87 90
    8 	0 97 96 0 0
    9 	0 0 89 0 0
    10 	95 99 0 0 0
    11 	0 0 96 97 0
    12 	0 0 0 93 98
    13 	94 91  0 0 0
    14 	0 83 87 0 0
    15 	0 0 98 97 98
    16 	0 0 0 93 86
    17 	98 83 99 98 81
    18 	93 87 92 96 98
    19 	0 0 0 89 92
    20 	0 99 96 95 81
    
    

    这题直接暴力就完事了,时间复杂度是20的5次方3.2E6,完全不会超时。

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    int visit[30],ans;
    using namespace std;
    struct people {
    	int score[6];
    }a[30];//存入同一个人的不同位置分数
    
    void dfs(int pos,int sum) {//sum是当前枚举分数,pos是当前枚举的位置。
    	if(pos==6) {
    		ans=max(ans,sum);
    		return ;
    	}
    	for(int i=1;i<=20;i  ) {
    		if(!visit[i]) {
    			visit[i]=1;
    			dfs(pos 1,sum a[i].score[pos]);
    			visit[i]=0;
    		}
    	}
    }
    int main()
    {
    	freopen("D:\MY\ce.txt","r",stdin);
    	int t;
    	ans=0;
    	for(int i=1;i<=20;i  ) {
    		visit[i]=0;
    		cin>>t;
    		for(int j=1;j<=5;j  )
    			cin>>a[i].score[j];//这个人在第i位的分数。
    	}
    	dfs(1,0);
    	cout<<ans<<endl;
    	return 0;
    }
    

    最后答案是490.



    B: 年号字串
    在这里插入图片描述
    这题是普通进制的转换,没什么特别。
    但是这里最重要的就是对于余数是零的要进行处理,将其转换为26,也就是Z。

    #include<iostream>
    char a[30],ans[30];
    using namespace std;
    void init() {
    	for(int i=0;i<26;i  )
    		a[i 1]=(char)('A' i);
    }
    int main()
    {
    	init();//初始化数组a,为A~Z。
    	int n;
    	while(cin>>n) {
    		int pos=0;
    		while(n) {
    			int t=n%26;
    			if(t==0) {//这一步中,对于余数是零的要转化为26, 
    				t=26;//所以n要减去26,t要是26。 
    				n-=26;
    			}
    			ans[pos  ]=a[t];
    			n/=26;
    		}
    		pos--;
    		for(int i=pos;i>=0;i--)
    			cout<<ans[i];
    		cout<<endl;
    	} 
    	return 0;
    }
    

    答案是BYQ.



    C: 数列求值
    在这里插入图片描述
    简单的递归,递归的时候磨去10000,保留最后4位数字,
    但是这里的第20190324项可能过于大,单纯的递归可能出不来结果。
    ~可以写个记忆化。
    ~或者写个for递推跑出来。
    ~再高级一点就是矩阵快速幂了。

    一、递推写法

    #include<iostream>
    #define mood 10000
    const int maxn=3e7;
    int a[maxn]={0,1,1,1};
    using namespace std;
    int main()
    {
    	for(int i=4;i<=20190324;i  )
    		a[i]=(a[i-1] a[i-2] a[i-3])%mood;
    	cout<<a[20190324];
    	return 0;
    }
     
    

    二、记忆化递归

    #include<iostream>
    #define mood 10000
    const int maxn=3e7;
    int a[maxn]={0,1,1,1};
    using namespace std;
    int dfs(int s) {
    	if(a[s])	return a[s];
    	a[s]=(dfs(s-1) dfs(s-2) dfs(s-3))%mood;
    	return a[s];
    }
    int main()
    {
    	int n=20190324;
    	printf("%d
    ",dfs(n));
    	return 0;
    }
     
    

    这个试过了,跑不出来,到十万多的时候就不行了
    三、矩阵快速幂

    #include<iostream>
    #define mood 10000
    typedef long long ll;
    const int N=3;
    using namespace std;
    struct unit {
    	ll a[N][N];
    };
    
    unit the(unit a,unit b) {
    	unit temp;
    	for(int i=0;i<N;i  )
    		for(int j=0;j<N;j  ) {
    			temp.a[i][j]=0;
    			for(int k=0;k<N;k  )
    				temp.a[i][j]=(temp.a[i][j] a.a[i][k]*b.a[k][j])%mood;
    		}
    	return temp;
    }
    int main() {
    	int n;
    	while(cin>>n) {
    		if(n<=3) {
    			cout<<1<<endl;
    			continue;
    		}
    		unit ans={
    			1,1,1,
    			0,0,0,
    			0,0,0
    		};
    		unit temp= {
    			1,1,0,
    			1,0,1,
    			1,0,0
    		};
    		n-=3;
    		while(n) {
    			if(n&1)	ans=the(ans,temp);
    			temp=the(temp,temp);
    			n>>=1;
    		}
    		cout<<ans.a[0][0]<<endl;
    	}
    	return 0;
    }
    

    答案是4659.



    D: 数的分解
    在这里插入图片描述

    #include<iostream>
    int ans[5]={1},sum;
    using namespace std;
    bool judge(int x) {
    	while(x) {
    		int t=x%10;
    		if(t==2||t==4)
    			return true;
    		x/=10;
    	}
    	return false;
    }
    int main()
    {
    	sum=0;
    	int n=2019;
    	for(int i=1;i<=n;i  ) {
    		if(judge(i))
    			continue;
    		for(int j=i 1;j<=n;j  ) {
    			if(i j>=n)
    				break;
    			if(judge(j)||i==j)
    				continue;
    			for(int k=j 1;k<=n;k  ) {
    				if(i j k>n)
    					break;
    				if(judge(k)||k==i||j==k)
    					continue;
    				if(i j k==n)
    					sum  ;
    			}
    		}
    	}
    	cout<<sum<<endl;
    	return 0;
    }
    

    直接暴力,一秒之内出结果,但是要注意,i<j<k这样才能保证,不会出现重复的情况,
    这里的剪枝除了有 i<j<k,
    还要注意当i j>=n || i j k>n的时候要直接break出去。
    本来想用dfs的递归的,但是一直剪枝出问题,出不来正确答案,就用这个for循环吧,

    答案40785.



    E: 迷宫
    这个看参考我的上一篇博客,2019蓝桥杯E题迷宫



    F: 特别数的和
    在这里插入图片描述

    #include<iostream>
    using namespace std;
    bool judge(int x) {
    	while(x) {
    		int t=x%10;
    		if(t==2||t==0||t==1||t==9)
    			return true;
    		x/=10;
    	}
    	return false;
    }
    int main()
    {
    	int n;
    	while(cin>>n) {
    		int sum=0;
    		for(int i=1;i<=n;i  )
    			if(judge(i))
    				sum =i;
    		cout<<sum<<endl;
    	}
    	return 0;
    }
    

    一个循环加一个judge函数判断数字是否含有2,0,1,9,
    直接暴力,最大10000的测试样例也是秒出,感觉比前面的题都更水。



    G:完全二叉树的权值
    在这里插入图片描述
    在这里插入图片描述
    只要判断当前值的数组下标是再哪一深度下就行了,第i层深度共有
    2(i-1)个数,这里的最大N<=100000,而217是131072,因此最多有17 1=18层

    #include<iostream>
    #include<cstring>
    #include<cmath> 
    typedef long long ll;
    ll a[20];//存放第i-1层的权值。
    using namespace std;
    int main()
    {
    	int n;
    	while(cin>>n) {
    		memset(a,0,sizeof(a));
    		int l;
    		for(int i=0;;i  )//寻找最大深度层。
    			if(n<=pow(2,i)) {
    				l=i;
    				break;
    			}
    		int pos=0,flag;
    		ll ans=0;
    		for(int i=0;i<=l;i  ) {
    			int longs=pow(2,i);
    			for(int j=0;j<longs&&pos  <n;j  ){//读入的操作,定义一个
    				ll temp;				//pos来保证读入的数字个数
    				cin>>temp;					 //与n是一样的。
    				a[i] =temp;
    			}
    			if(a[i]>ans) {
    				ans=a[i];
    				flag=i 1;//i是深度-1,所以真正深度应该是i 1。
    			}
    		}
    		cout<<flag<<endl;
    	}
    	return 0;
    }
    


    H:等差数列
    在这里插入图片描述在这里插入图片描述

    #include<iostream>
    #include<cmath>
    #include<algorithm>
    const int maxn=100010;
    int a[maxn];
    using namespace std;
    int gcd(int x,int y) {
    	if(y==0)	return x;
    	return gcd(y,x%y);
    }
    int main()
    {
    	int n;
    	while(cin>>n) {
    		for(int i=0;i<n;i  )
    			cin>>a[i];
    		sort(a,a n);
    		int mina=a[0],maxa=a[n-1];
    		for(int i=1;i<n;i  )
    			a[i-1]=a[i]-a[i-1];
    		sort(a,a n-1);
    		if(a[0]==0) {
    			cout<<n<<endl;
    			continue;
    		}
    		int step=a[0];
    		for(int i=1;i<n-1;i  ) {
    			if(a[i]%step==0)
    				continue;
    			step=gcd(step,a[i]);
    		}
    		cout<<(maxa-mina)/step 1<<endl;
    	}
    	return 0;
    }
    

    思路就是排序找对大的数和最小的数,然后求得有序数的两数之间的差,然后再找这些差之间的最大公因数,
    最后对求得的公因数进行分类,
    为零时,就是常数列,所以长度时n
    不为零时,长度是(最大值减最小值)/所得的公因数 1。


    写了这一题,我真正明白了暴力杯这个称号,我都这么折腾了,他还是不超时,以后有什么题不能优化,直接暴力就完事了。



    I:后缀表达式.
    在这里插入图片描述
    这道题就是有点难搞清楚n,m之间的关系,
    假设m为零,答案很简单了,就是n 1个数相加。
    当m不为零时,我们可以通过括号把所有的加号变成减号。所以这道题目就变成了,都是加号,或者都是减号的问题,都是加号的问题上面已近考虑完了,
    下面我们来考虑都是减号的问题,假设符号数时n m=L减号我们又可以通过加括号的方式,减去1~~L个数,最少减去一个数,最多减去L个数,
    于是这里有两种特殊情况:
    全是负数,这里我们应当选取最大的负数不添加减号。
    全是正数,这里我们应但选取最小的负数添加减号。

    #include<iostream>
    typedef long long ll;
    const int maxn=2e5 10;
    ll a[maxn];
    using namespace std;
    int main()
    {
    	int n,m,l;
    	cin>>n>>m;
    	l=n m 1;
    	ll minzheng=2000000000,maxfu=-2000000000;
    	int zheng=0,fu=0;
    	for(int i=0;i<l;i  ) {
    		cin>>a[i];
    		if(a[i]>0) {
    			zheng  ;
    			minzheng=min(minzheng,a[i]);
    		}
    		else if(a[i]<0) {
    			fu  ;
    			maxfu=max(maxfu,a[i]);	
    		}
    	}
    	ll sum=0;
    	if(m==0) {
    		for(int i=0;i<l;i  )
    			sum =a[i];
    		cout<<sum<<endl;
    	}
    	else {
    		if(zheng==l) {
    			for(int i=0;i<l;i  )
    				sum =a[i];
    			cout<<sum-2*minzheng<<endl;
    		}
    		else if(fu==l) {
    			for(int i=0;i<l;i  )
    				sum-=a[i];
    			cout<<sum 2*maxfu<<endl;
    		}
    		else {
    			for(int i=0;i<l;i  ) {
    				if(a[i]>0)
    					sum =a[i];
    				else
    					sum-=a[i];
    			}
    			cout<<sum<<endl;
    		}
    	}
    	return 0;
    }
    


    J: 灵能传送.
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述
    菜鸡的我看完这道题,就只会一个公式,( a[i-1] , a[i] , a[i-1] ) 转变后变成了,
    ( a[i-1] a[i] , -a[i] , a[i 1] a[i] ),
    然后想到要用前缀和或者差分,但还是不知道怎么写。在B站看了yxc大佬的acwing视频后,才明白如何写

    这道题大致分为两种情况,在对情况进行讨论前,我们设定一些必要的约定。
    数组读入从1开始,一直到n,我们假设sum数组,sum[i]表示的是第i项的前缀和,设定s0=0,对上述公式的变换就可以写成
    (sum[i-1] , sum[i] , sum[i 1])变成(sum[i] , sum[i-1] , sum[i 1])
    这里不难发现,就是对下标从 1~(n-1)的前缀和数组进行交换,
    —、第一种情况,如图
    这是最佳排列方式
    这是第一种情况的图
    假设最大的一项和最小的一项在第0个和第n个前缀和中。
    要保证每两项之间的差的绝对值最小,只有降序排列(最大在首,最小在尾。),或者升序排列(最小在首,最大在尾。)

    二、第二种情况,如图
    这个是这种情况的最佳排列方式
    在这里插入图片描述
    最大和最小不一定都在首尾,先把选点排序,
    这里我们的选点方式应该是跳跃式的选点方式,如果,有两个选点相连,那么一定有,两个选点的间距大于二,那么最大值一定会比这两个相连的选点的值更大,

    我们把因为第0个位置和第n个位置不能变,
    我们把所有选点投射到y轴上,从数值为sum[0]的点开始向下,step=2的步长选点,从数值为sum[n]的点开始向上选点,step也是2,然后把剩下的点,按照升序补齐中间的一段。在对整个前缀和求出两个之间绝对值最大的数。

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    typedef long long ll;
    const int maxn=300010;
    ll sum[maxn],a[maxn];//sum是用存放排序前的前缀和数组,a是用来存放最后答案的前缀和数组。
    int visit[maxn];
    using namespace std;
    int main()
    {
    //	freopen("D:\MY\ce.txt","r",stdin);
    	int t;
    	cin>>t;
    	while(t--) {
    		int n;
    		cin>>n;
    		sum[0]=0;//初始化第一个前缀和为0.
    		for(int i=1;i<=n;i  ) {
    			ll t;
    			cin>>t;
    			sum[i]=sum[i-1] t;//存放初始前缀和。
    		}
    		ll s0=sum[0],sn=sum[n];
    		if(s0>sn)	swap(s0,sn);//交换顺序,满足s0<sn,便于运算,
    		sort(sum,sum n 1);//对前缀和数组排序,
    		s0=lower_bound(sum,sum n 1,s0)-sum;//找到s0位于sum数组种的位置。
    		sn=lower_bound(sum,sum n 1,sn)-sum;//找到sn位于sum数组中的位置。
    		int l=0,r=n;
    		memset(visit,0,sizeof(visit));
    		for(int i=s0;i>=0;i-=2) {//从s0开始向下找数。
    			a[l  ]=sum[i];
    			visit[i]=1;
    		}
    		for(int i=sn;i<=n;i =2) {//从sn开始向上招数。
    			a[r--]=sum[i];
    			visit[i]=1;
    		}
    		for(int i=0;i<=n;i  )//用剩下的数补齐a数组。
    			if(!visit[i])
    				a[l  ]=sum[i];
    		ll ans=0;
    		for(int i=1;i<=n;i  )
    			ans=max(ans,abs(a[i]-a[i-1]));//最后得到绝对值最大的数,
    		cout<<ans<<endl;
    	}
    	return 0;
    }
    

    终于写完了这篇题解了。
    心得:
    除了后两道题是我真不会的,但是前面的题在oj上提交我也不能保证一次就对。还有就是,我这次真正明白了什么是蓝桥杯,“暴力杯”了,蓝桥杯的题实在不能优化,就直接暴力完事了。

  • 相关阅读:
    Impala源码之订阅发布系统的实现
    Kylin性能调优记——业务技术两手抓
    The Beam Model:Stream &amp; Tables翻译(上)
    手把手教你搭建hadoop+hive测试环境(新手向)
    使用 Apache Atlas 进行数据治理
    类似gitlab代码提交的热力图怎么做?
    3分钟掌握一个有数小技能:回头客分析
    3分钟掌握一个有数小技能:制作动态标题
    uva 10404 Bachet's Game(完全背包)
    POJ3771+Prim
  • 原文地址:https://www.cnblogs.com/lifehappy/p/12601203.html
Copyright © 2020-2023  润新知