蓝桥杯第九届(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