[蓝桥杯解题报告]第九届蓝桥杯大赛省赛2018(软件类)真题C++A组 Apare_xzc

蓝桥杯第九届(2018年)省赛软件类C++A组解题报告

Apare_xzc 2020/3/8


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


1. 分数

在这里插入图片描述

分析:

        原式 = 1+1-(2^19) = 1+(2^19-1)/2^19 = (2^19+2^19-1)/2^19 = (2^20-1)/(2^19)

代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int up = (1<<20)-1;
	int down = (1<<19);
	int g = __gcd(up,down);
	up/=g; down/=g;
	cout<<up<<"/"<<down<<endl;
	return 0;
} 

在这里插入图片描述

答案:1048575/524288


2. 星期一

在这里插入图片描述

分析:

        可以用日历做吧。知道今天是星期几,几月几号,就可一推出2000年12月31日是星期几,就可以算出来了。

代码:

#include <bits/stdc++.h>
using namespace std;
int isLeap(int y) {
	if(y%400==0||y%4==0&&y%100!=0)return 1;
	return 0;
}
int main() {
	int tot = 0;
	for(int i=1901; i<=2000; ++i)
		tot += 365+isLeap(i);
	--tot;
	int t2 = 0;
	for(int i=2001; i<=2019; ++i) 
		t2 += 365 + isLeap(i);
	t2 += 31+29+8; //今天是2020年3月8日 星期日
	cout<<"t2 = "<<t2<<endl;
	t2%=7;
	cout<<t2<<endl; //t2 = 0
	//说明2000年12月31日是星期日
	printf("%d / %d = %d ... %d\n",tot,7,tot/7,tot%7);
	//36524 / 7 = 5217 ... 5 说明1901/1/1是周日往回数5天,为周二 
	cout<<tot/7<<endl; //5217
	return 0;
}

答案:5217

在这里插入图片描述


3. 乘积尾零

在这里插入图片描述

输入数据:

5650 4542 3554 473 946 4114 3871 9073 90 4329 
2758 7949 6113 5659 5245 7432 3051 4434 6704 3594 
9937 1173 6866 3397 4759 7557 3070 2287 1453 9899 
1486 5722 3135 1170 4014 5510 5120 729 2880 9019 
2049 698 4582 4346 4427 646 9742 7340 1230 7683 
5693 7015 6887 7381 4172 4341 2909 2027 7355 5649 
6701 6645 1671 5978 2704 9926 295 3125 3878 6785 
2066 4247 4800 1578 6652 4616 1113 6205 3264 2915 
3966 5291 2904 1285 2193 1428 2265 8730 9436 7074 
689 5510 8243 6114 337 4096 8199 7313 3685 211 

分析:

        我们只要把每个数都分解,求出因子为2的个数和因子为5的个数,取较小值即可。

代码:

#include <bits/stdc++.h>
using namespace std;
int main() {
	freopen("in_C.txt","r",stdin);
	int x;
	int cnt2 = 0, cnt5 = 0;
	while(cin>>x) {
		while(x%2==0) x/=2,cnt2++;
		while(x%5==0) x/=5,cnt5++;
	}
	cout<<min(cnt2,cnt5)<<endl; //31
	return 0;
} 

答案:31

在这里插入图片描述


4. 第几个幸运数字

在这里插入图片描述
计算59084709587505是第几个幸运数字。

分析:

        我们可以处理出所有比59084709587505小的幸运数,然后就知道它是第几个了。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL M = 59084709587505ll;
LL p3[100]={1},p5[100]={1},p7[100]={1};
LL r[1000000];
int main()
{
	int c3,c5,c7;
	for(int i=1;;++i) {
		p3[i] = p3[i-1]*3;
		if(p3[i]>M) {
			c3 = i-1;break;
		}
	}
	for(int i=1;;++i) {
		p5[i] = p5[i-1]*5;
		if(p5[i]>M) {
			c5 = i-1;break;
		}
	}
	for(int i=1;;++i){
		p7[i] = p7[i-1]*7;
		if(p7[i]>M) {
			c7 = i-1;break;
		}
	}
	int cnt = 0;
	for(int i=0;i<=c3;++i) {
		for(int j=0;j<=c5;++j) {
			if(p3[i]>=M/p5[j]) break;
			for(int k=0;k<=c7;++k) {
				if(p3[i]*p5[j]>M/p7[k]) break;
				r[cnt++] = p3[i]*p5[j]*p7[k];
			}
		}
	}
	sort(r,r+cnt);
	for(int i=0;i<cnt;++i)
		cout<<r[i]<<" ";cout<<endl; 
	cout<<"cnt = "<<cnt<<endl; 
	return 0;
} 

答案:1905

在这里插入图片描述


5. 打印程序

在这里插入图片描述
在这里插入图片描述

题目代码如下:

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

void show(char* buf, int w){
	int i,j;
	for(i=0; i<w; i++){
		for(j=0; j<w; j++){
			printf("%c", buf[i*w+j]==0? ' ' : 'o');
		}
		printf("\n");
	}
}

void draw(char* buf, int w, int x, int y, int size){
	if(size==1){
		buf[y*w+x] = 1;
		return;
	}
	
	int n = _________________________ ; //填空
	draw(buf, w, x, y, n);
	draw(buf, w, x-n, y ,n);
	draw(buf, w, x+n, y ,n);
	draw(buf, w, x, y-n ,n);
	draw(buf, w, x, y+n ,n);
}

int main()
{
	int N = 3;
	int t = 1;
	int i;
	for(i=0; i<N; i++) t *= 3;
	
	char* buf = (char*)malloc(t*t);
	for(i=0; i<t*t; i++) buf[i] = 0;
	
	draw(buf, t, t/2, t/2, t);
	show(buf, t);
	free(buf);
	
	return 0;
}

答案:size/3 (从输入的行数即可得到)

在这里插入图片描述


6. 航班时间

在这里插入图片描述
在这里插入图片描述

样例输入:

3
17:48:19 21:57:24
11:05:18 15:14:23
17:21:07 00:31:46 (+1)
23:02:41 16:13:20 (+1)
10:19:19 20:41:24
22:19:04 16:41:09 (+1)

样例输出:

04:09:05
12:10:39
14:22:05

分析:

        我们可以计算出往返的两次时间差,然后相加即可抵消时差,求算数平均数即为答案。

代码:

#include <bits/stdc++.h>
using namespace std;
char str[100];
void show(int x) {
	int s,m,h;
	s = x%60;
	x/=60;
	m = x%60;
	h = x/60;
	printf("%02d:%02d:%02d\n",h,m,s);
}
int getDif() {
	int sh,sm,ss,eh,em,es,add=0,stime,etime,dif;
	cin.getline(str,100);
	sscanf(str,"%d:%d:%d %d:%d:%d (+%d)",&sh,&sm,&ss,&eh,&em,&es,&add);
	eh += add*24;
	stime = (sh*60+sm)*60+ss;
	etime = (eh*60+em)*60+es;
	dif = etime-stime;
	return dif;
}

int main() {
//	freopen("in_F.txt","r",stdin);
	int T;
	cin>>T;
	int dif1,dif2,ans;
	cin.getline(str,100);
	while(T--) {
		dif1 = getDif();
		dif2 = getDif();
		ans = (dif1+dif2)/2;
		show(ans);
	}
	return 0;
}

在这里插入图片描述


7. 三体攻击

在这里插入图片描述
在这里插入图片描述

样例输入:

2 2 2 3
1 1 1 1 1 1 1 1
1 2 1 2 1 1 1
1 1 1 2 1 2 1
1 1 1 1 1 1 2

样例输出:

2

分析:

        分析得,暴力可以得70分。那就写暴力吧。三维的数据结构不会写。网上有个OI选手,写了一篇二分答案+三维差分check的题解,可以拿100分。

代码:

#include <bits/stdc++.h>
using namespace std;
int a[1000000+10];
int main() {
	int A,B,C,m,n,la,ra,lb,rb,lc,rc,h,id;
	scanf("%d%d%d%d",&A,&B,&C,&m);
	n = A * B * C;
	for(int i=1;i<=n;++i)
		scanf("%d",a+i);
	int ans = -1;
	for(int ca=1;ca<=m;++ca) {
		scanf("%d%d%d%d%d%d%d",&la,&ra,&lb,&rb,&lc,&rc,&h);
		if(ans!=-1) continue;
		for(int i=la;i<=lb&&ans==-1;++i) {
			for(int j=la;j<=lb&&ans==-1;++j) {
				for(int k=lc;k<=rc;++k) {
					id = ((i-1)*B+j-1)*C+k;
					a[id] -= h;
					if(a[id]<0) {
						ans = ca; break;
					}
				}
			}
		}
	}
	cout<<ans<<endl; 
	return 0;
}

在这里插入图片描述


8. 全球变暖

在这里插入图片描述
在这里插入图片描述

样例输入:

7 
.......
.##....
.##....
....##.
..####.
...###.
.......  

样例输出:

1

分析:

        dfs判连通,然后dfs淹大陆,再dfs即可。见代码

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
char a[N][N];
bool v[N][N];
int n;
int dx[] = {0,0,1,-1};
int dy[] = {-1,1,0,0};
bool ok(int x,int y)
{
	return x>=0&&x<n&&y>=0&&y<n;
}
void dfs(int x,int y) {
	if(v[x][y]) return;
	v[x][y] = true;
	for(int i=0; i<4; ++i) {
		int s = x + dx[i], t = y + dy[i];
		if(!ok(s,t)||v[s][t]||a[s][t]!=a[x][y]) continue;
		dfs(s,t);
	}
}
int main() {
	freopen("in_H.txt","r",stdin);
	cin>>n;
	for(int i=0; i<n; ++i)
		scanf("%s",a[i]);
	int cnt = 0;
	for(int i=0; i<n; ++i) {
		for(int j=0; j<n; ++j) {
			if(a[i][j]=='.'||v[i][j]) continue;
			dfs(i,j);
			++cnt;
		}
	}
	vector<pair<int,int> > ve;
	for(int i=0; i<n; ++i) {
		for(int j=0; j<n; ++j) {
			if(a[i][j]=='.') continue;
			bool tag = true;
			for(int k=0;k<4;++k)
			{
				int x = i+dx[k], y = j+dy[k];
 				if(!ok(x,y)) continue;
				if(a[x][y]=='.') {
					tag = false; break;
				}
			}
			if(!tag) ve.push_back(make_pair(i,j));
		}
	}
	int sz = ve.size();
	for(int i=0;i<sz;++i)
		a[ve[i].first][ve[i].second] = '.';
	memset(v,false,sizeof(v));

 	int cnt2 = 0;
	for(int i=0;i<n;++i)
		for(int j=0;j<n;++j) {
			if(v[i][j]||a[i][j]=='.') continue;
			dfs(i,j); ++cnt2;
		}
	cout<<cnt-cnt2<<endl;
	return 0;
}

在这里插入图片描述


9. 倍数问题

在这里插入图片描述在这里插入图片描述

分析:

        由于k<=1000很小,所以我们从这里找突破口。我们把%k余数为相同的数放到同一个列表里,然后从大到小排序。k的倍数,余数要么都是0,要么三个数%k的余数之和为k。我们可以dfs,找出三个数之和为K的所有情况。

代码:

#include <bits/stdc++.h>
using namespace std;
int a[100005];
vector<int> v[1000];
bool cmp(int x,int y) {
	return x>y;
}
int main() {
	int n,k;
	scanf("%d%d",&n,&k);
	for(int i=1; i<=n; ++i)
		scanf("%d",a+i),v[a[i]%k].push_back(a[i]);
	for(int i=0; i<k; ++i)
		if(v[i].size()) sort(v[i].begin(),v[i].end(),cmp);
	int ans = -1000;
	if(v[0].size()>=3) ans = v[0][1]+v[0][2]+v[0][0];
	for(int i=0; i*3<=k; ++i) {
		for(int j=i; i+j*2<=k; ++j) {
			int t = k-i-j;
			if(i==j&&j==t) {
				if(v[i].size()>=3) ans = max(ans,v[i][0]+v[i][1]+v[i][2]);
			} else if(i==j) {
				if(v[i].size()>=2&&v[t].size()>=1) ans = max(ans,v[i][0]+v[i][1]+v[t][0]);
			} else if(j==t) {
				if(v[j].size()>=2&&v[i].size()>=1) ans = max(ans,v[i][0]+v[j][0]+v[j][1]);
			} else {
				if(v[i].size()&&v[j].size()&&v[t].size()) ans = max(ans,v[i][0]+v[j][0]+v[t][0]);
			}
		}
	}
	cout<<ans<<endl;
	return 0;
}

在这里插入图片描述


10. 付账问题

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

样例输入1:

5 2333
666 666 666 666 666

样例输出1:

0.0000

样例输入2:

10 30
2 1 4 7 4 8 3 6 4 7

样例输出2:

0.7928

分析:

        方差最小,就是相互最接近,每个数都和平均数差最小。我们先求出平均数。带的钱不足平均数的,全部拿出来。剩下的帐和剩下的人再求平均数,然后按照新的平均数出钱。这样贪心,方差最小。

代码:

#include <bits/stdc++.h>
using namespace std;
double a[500008];
int main() {
	int n;
	double tot,ever;
	scanf("%d%lf",&n,&tot);
	for(int i=1; i<=n; ++i)
		scanf("%lf",a+i);
	ever = tot/n;
	sort(a+1,a+1+n);
	int s = n+1;
	double sum = 0;
	for(int i=1; i<=n; ++i) {
		if(a[i]*n>tot) {
			s = i;
			break;
		}
		sum += a[i];
	}
	if(s==n+1) {
		puts("0.0000");
		return 0;
	}
	ever = (tot-sum)/(n+1-s);
	for(int i=s; i<=n; ++i) a[i] = ever;
	ever = tot / n;
	double All = 0;
	for(int i=1; i<=n; ++i)
		All += (ever-a[i])*(ever-a[i]);
	All /= n;
	All = sqrt(All);
	printf("%.4f\n",All);
	return 0;
}

在这里插入图片描述


2020.3.13
1:17
xzc


猜你喜欢

转载自blog.csdn.net/qq_40531479/article/details/104831344