2016年第七届蓝桥杯省赛C语言B组题解

之前一次撸完题解,复制记事本上题目的时候这网页卡住了(撤回都撤回不了),回来啥都没了,在线自闭。再写就懒了,就写那些让我好好思考的题的题解。看最近蓝桥杯的访问量较多,还是决定把题补全,但会没题目,只有答案和注释里的题解。

1.煤球数量

简单的前缀和
答案:171700

#include <iostream>
using namespace std;
int main()
{
    long long int i,ans[110];
    ans[1]=1;
    for(i=2;i<=100;i++)
        ans[i]=ans[i-1]+i;
    for(i=2;i<=100;i++)
        ans[i]+=ans[i-1];
    cout<<ans[100];
    return 0;
} 

2.生日蜡烛

又是简单的前缀和,但要注意答案加一,前缀和剪掉的是上一年的结尾。
答案:26 说不定他就活到了236岁呢

#include <iostream>
using namespace std;
int main()
{
    int num[100],i,j;
    num[0]=0;
    for(i=1;i<=100;i++)
       num[i]=num[i-1]+i;
    for(i=100;i>=0;i--)
       for(j=0;j<=100;j++)
            if(num[i]-num[j]==236)
           {
               cout<<j+1<<endl;
               return 0;
           } 
} 

3.凑算式

全排列暴力 暴力大法好
反正题目里没有0,随便排(网上查的没0,学校给的有0,反正我偷懒写没0的)
next_permutation(a+1,a+10)是algorithm头文件下的一个全排列函数,也是在这才学会的。
注意do while
答案:29

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int main()
{
    double n1,n2;
    int a[10],i,ans=0;
    for(i=1;i<10;i++)
        a[i]=i;
    do
    {
        n1=1.0*a[2]/a[3];
        n2=1.0*(100*a[4]+10*a[5]+a[6])/(100*a[7]+10*a[8]+a[9]);
        if(fabs(a[1]+n1+n2-10)<1e-6) ans++; 
    }while(next_permutation(a+1,a+10));
    cout<<ans<<endl;
    return 0;
}

4.快速排序

没啥好讲的,快排都做烂了,看懂过程就行。
**答案:swap(a,p,j); **

5.抽签

抽签
X星球要派出一个5人组成的观察团前往W星。
其中:
A国最多可以派出4人。
B国最多可以派出2人。
C国最多可以派出2人。

那么最终派往W星的观察团会有多少种国别的不同组合呢?
下面的程序解决了这个问题。
数组a[] 中既是每个国家可以派出的最多的名额。
程序执行结果为:
DEFFF
CEFFF
CDFFF
CDEFF
CCFFF
CCEFF
CCDFF
CCDEF
BEFFF
BDFFF
BDEFF
BCFFF
BCEFF
BCDFF
BCDEF

(以下省略,总共101行)

#include <stdio.h>
#define N 6
#define M 5
#define BUF 1024
void f(int a[],int k,int m,char b[])
{
    int i,j;
    if(k==N)
    { 
        b[M]=0;
        if(m==0) printf("%s\n",b);
        return;
    }
    for(i=0;i<=a[k];i++)
    {
        for(j=0; j<i; j++) 
            b[M-m+j]=k+'A';
        f(a,k+1,m-j,b);
    }
}
int main()
{ 
    int a[N]={4,2,2,1,1,3};
    char b[BUF];
    f(a,0,M,b);
    return 0;
}

解:
此类填空题的核心是看懂实参形参的含义:
f(数组首地址,国家,剩余人数,数组首地址)

6.方格填数

在这里插入图片描述
答案:1580

解:
暴力填入,dfs判断是否正确(暴力大法好)

#include <iostream>
#include <cmath>
using namespace std;
int aa[3][4],dir[8][2]={1,0,-1,0,0,1,0,-1,1,1,1,-1,-1,1,-1,-1},vis[10],ans;
bool check()//判断
{
    int i,j,k;
    for(i=0;i<3;i++)
        for(j=0;j<4;j++)
            for(k=0;k<8;k++)
            {
                int x=i+dir[k][0],y=j+dir[k][1];
                if(x>=0&&x<=2&&y>=0&&y<=3)
                    if(abs(aa[x][y]-aa[i][j])==1)
                        return false;
            }
    return true;
}
void func(int a,int b)//填入
{
    int i,j;
    if(a==2&&b==3)
    {
        if(check()) ans++;
        return;
    } 
    for(i=0;i<=9;i++)
        if(!vis[i]) 
        {
            vis[i]=1;
            aa[a][b]=i;
            if(b==3) func(a+1,0);
            else func(a,b+1);
            vis[i]=0;
        }
}
int main()
{
    aa[0][0]=0x7fffffff;
    aa[2][3]=0x7fffffff;
    func(0,1);
    cout<<ans;
    return 0;
} 

7.剪邮票

如【图1.jpg】, 有12张连在一起的12生肖的邮票。
现在你要从中剪下5张来,要求必须是连着的。
(仅仅连接一个角不算相连)
比如,【图2.jpg】【图3.jpg】中,粉红色所示部分就是合格的剪取。
请你计算,一共有多少种不同的剪取方法。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
答案:116

解:
关键是如何找出并不重复。还是暴力枚举然后dfs判断。
为防止重复可以保持从小到大的顺序枚举,再判断其是否是联通即可。

#include <iostream>
#include <cstring>
using namespace std;
bool vis[13];
int note[5],dir[4][2]={1,0,-1,0,0,1,0,-1},ans,count,mp[4][5]; 
void dfs(int a,int b)//搜索
{
    if(count==5) return;                  //枚举的5个数联通
    int i,j;
    for(i=0;i<4;i++)
    {
        int x=a+dir[i][0],y=b+dir[i][1];
        if(x>=1&&x<=3&&y>=1&&y<=4&&!vis[mp[x][y]])
            for(j=0;j<5;j++)
                if(mp[x][y]==note[j])
                {
                    count++;
                    vis[note[j]]=true;
                    dfs(x,y);
                }
    }
}
int main()
{
    for(int i=1;i<=3;i++)
        for(int j=1;j<=4;j++)
            mp[i][j]=(i-1)*4+j;//生成图1,用于dfs搜索
    for(int i=1;i<=8;i++)
    {
        note[0]=i;
        for(int j=i+1;j<=9;j++)
        {
            note[1]=j;
            for(int k=j+1;k<=10;k++)
            {
                note[2]=k;
                for(int l=k+1;l<=11;l++)
                {
                    note[3]=l;
                    for(int m=l+1;m<=12;m++)
                    {
                        memset(vis,false,sizeof(vis));
                        note[4]=m;                       //枚举填入
                        vis[i]=true;             
                        count=1;
                        dfs((i-1)/4+1,(i-1)%4+1);        //找出对应坐标用于搜索
                        if(count==5) ans++;
                    }
               }
            }
        }
    }
    cout<<ans;
    return 0; 
}

8.四平方和

暴力一下 不知道可不可以过,

#include <iostream>
using namespace std;
int n,i,j,k,l;
void func()
{
    for(i=0;i*i<=n;i++)
        for(j=i;i*i+j*j<=n;j++)
            for(k=j;i*i+j*j+k*k<=n;k++)
                for(l=k;i*i+j*j+k*k+l*l<=n;l++)
                    if(i*i+j*j+k*k+l*l==n)
                    {
                        cout<<i<<" "<<j<<" "<<k<<" "<<l;
                        return;
                    }              
}
int main()
{
    cin>>n;
    func();
    return 0; 
} 

9.交换瓶子

标准贪心,从前往后,哪个位置不对,就和后面对应的换。

#include <iostream>
using namespace std;
void swap(int a[],int b,int c)//交换,话说algorithm里好像有swap函数
{
    int t=a[b];
    a[b]=a[c];
    a[c]=t;
}
int main()
{
    int a[10010],n,i,j,ans=0,loca[10010];
    cin>>n;
    for(i=1;i<=n;i++)
    {
        cin>>a[i];//输入
        loca[a[i]]=i;//每个瓶子的位置,便于O(1)查询
    } 
    for(i=1;i<=n;i++)
    {
        if(loca[i]==i) continue;//位置对则继续
        loca[a[i]]=loca[i];//换位置的值
        swap(a,i,loca[i]);//换值
        ans++;
        loca[i]=i;
    }
    cout<<ans<<endl;
    return 0;
} 

10.最大比例

X星球的某个大奖赛设了M级奖励。每个级别的奖金是一个正整数。
并且,相邻的两个级别间的比例是个固定值。
也就是说:所有级别的奖金数构成了一个等比数列。比如:
16,24,36,54
其等比值为:3/2
现在,我们随机调查了一些获奖者的奖金数。
请你据此推算可能的最大的等比值。
输入格式:
第一行为数字N,表示接下的一行包含N个正整数
第二行N个正整数Xi(Xi<1 000 000 000 000),用空格分开。每个整数表示调查到的某人的奖金数额
要求输出:
一个形如A/B的分数,要求A、B互质。表示可能的最大比例系数
测试数据保证了输入格式正确,并且最大比例是存在的。
例如,输入:
3
1250 200 32
程序应该输出:
25/4
再例如,输入:
4
3125 32 32 200

程序应该输出:
5/2
再例如,输入:
3
549755813888 524288 2
程序应该输出:
4/1
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 3000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。

解:
题意:现在有一堆被打乱了的等比数列,有的数可能缺,有的数可能出现多次,要你找可能存在的最大公比。
所以先升序排列并排除重复的数字,形成一个残缺的等比数列。前后相除得出比(分数形式,找最大公因数约分,分子分母分开存,对分子分母分开处理结果不变),定义最大公比为q,把他们看成qa1,qa2……(此时所有的数都与某一数成倍数关系)找出a1,a2,a3……an的最大公因数(不是qa1,qa2……的)即可,最后分别输出分子和分母的q。(解法:对a1,a2,a3……an用辗转相减,指数相减相当于原数相除)。

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long int ll;
ll gcd(ll a,ll b)//辗转相除
{
    return b? gcd(b,a%b):a;
}
ll gcdjian(ll a,ll b)//辗转相减的另一种使用
{
    if(a==b) return a;
    if(a>b) return gcdjian(b,a/b);
    else return gcdjian(b,a); 
} 
int main() 
{
    ll n,i,j,a[10000],a1[10000],a2[10000],t1,t2,ans1,ans2,len=0;
    double ans=0x7fffffff;
    cin>>n;
    for(i=0;i<n;i++)
        cin>>a[i];
    sort(a,a+n);
    for(i=1;i<n;i++)
    {
        if(a[i]==a[i-1]) continue;
        t1=gcd(a[i],a[i-1]); 
        a1[++len]=a[i]/t1;a2[len]=a[i-1]/t1;//约分
    }
    t1=a1[1];t2=a2[1];
    for(i=2;i<=len;i++)
    {
        t1=gcdjian(t1,a1[i]);
        t2=gcdjian(t2,a2[i]);
    }
    cout<<t1<<"/"<<t2;
    return 0;
}

时间复杂度怎样我不会算。。不知道能不能过,感觉没问题

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值