[藍橋杯解題報告]第九屆藍橋杯大賽省賽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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章