2016蓝桥杯题解

2018年的蓝桥杯也快开始了,去年我没有报。今年打算参加一次。本来报的A组,
但是评估了一下自己的实力。去A组可能就是个炮灰。因为鄙人是电子专业的,开始
做算法题大概一个月多点,中间夹杂着过年的放纵,开学的复习。现在总结一下2016蓝
桥杯的题。用的时间可能有4个半小时吧。题基本上都是自己做的,除了第九题。

题目我就不去复制了,只写解法。

(代码中的红色是因为我直接点了html/xml的格式)

第一题 煤球数目

送分题。找规律,1,1+2,1+2+3...

开个数组,记录每层的,一个总的加上。得结果171700

#include <iostream>

using namespace std;
int dp[102];
int main()
{
    int i;
    dp[0]=0;
    int sum=0;
    for(i=1;i<=100;i++){
        dp[i]=dp[i-1]+i;
        sum+=dp[i];
    }
    cout<<sum<<endl;
    return 0;
}

第二题 生日蜡烛

送分题。穷举,从一岁开始,每次都一直加,知道超过236,等于的话就推出得到结果。

#include <iostream>

using namespace std;
int dp[300];
int main()
{
    int i;
    for(i=1;i<=236;i++){
        int j=i,sum=0;
        int flag=0;
        while(1){
            sum+=j++;
            if(sum==236){flag=1;break;}
            if(sum>236)break;
        }
        if(flag)break;
    }
    cout << i << endl;
    return 0;
}

第三题 凑算式

这题就不是送分题了。因为有两个点,一个是要想到这里面的分子式有可能两个加起来是整数。
第二个是分子除以分母不好处理,要想到都变换一下,两边都乘两个分母(C,GHI)。
直接用next_permutation()函数进行枚举,然后判断是否可以。如果两个点有一个卡住了,那么就

很可能算出错误答案。

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
int a[20];
void permutation(){
    int s1,s=0;
    int s2,s3,m1,m2;
    do{
       m1=a[2];//分母C
       m2=(100*a[6]+10*a[7]+a[8]);//分母GHI
       s1=a[0]*m1*m2;//s1,s2,s3是左边的三项
       s2=a[1]*m2;
        s3=(100*a[3]+10*a[4]+a[5])*m1;
        if(s1+s2+s3==10*m1*m2){
            s++;
        }
    }while(next_permutation(a,a+9));
    cout<<s<<endl;
}
int main()
{
    int i;
    for(i=0;i<9;i++){
        a[i]=i+1;
    }
    permutation();
    return 0;
}

第四题 快速排序

送分题 虽然我没学过快排,但是题目中已经说清楚了。看懂代码,然后直接就能得出答案。

swap(a,p,j);

第五题 抽签

这个题是卡住我许久的题。原因是错误的把画横线的部分当作j循环下的了。首先肯定要填f(x,x,x,x),其中第一个和第四个肯定不变。k代表字母,用完了肯定+1,然后m是选了多少个,通过分析代码,是选了i个a[k],所以传递的就是m-i。

f(a,k+1,m-i,b);

第六题方格填数

两种方法,一种是直接dfs,一个数一个数填,但是会很慢,而且容易出错。

第二种还是用next_permutation函数,枚举所有的可能,判断一下就行。会写就很容易,还不容易错。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int a[10];
int sum=0;
bool if_can(){
    if(abs(a[0]-a[1])==1||abs(a[1]-a[2])==1)return false;
    if(abs(a[3]-a[4])==1||abs(a[4]-a[5])==1)return false;
    if(abs(a[5]-a[6])==1||abs(a[7]-a[8])==1)return false;
    if(abs(a[8]-a[9])==1||abs(a[0]-a[3])==1)return false;
    if(abs(a[0]-a[4])==1||abs(a[0]-a[5])==1)return false;
    if(abs(a[1]-a[4])==1||abs(a[1]-a[5])==1)return false;
    if(abs(a[1]-a[6])==1||abs(a[2]-a[5])==1)return false;
    if(abs(a[2]-a[6])==1||abs(a[3]-a[7])==1)return false;
    if(abs(a[3]-a[8])==1||abs(a[4]-a[7])==1)return false;
    if(abs(a[4]-a[8])==1||abs(a[4]-a[9])==1)return false;
    if(abs(a[5]-a[8])==1||abs(a[5]-a[9])==1)return false;
    if(abs(a[6]-a[9])==1)return false;
    return true;
}
void permutation(){
    do{
        if(if_can()){
            sum++;
        }
    }
    while(next_permutation(a,a+10));
}
int main(){
    for(int i=0;i<10;i++){
        a[i]=i;
    }
    permutation();
    cout<<sum<<endl;
}

第七题 剪邮票

这道题也花了不少时间去想,想直接DFS吧,又怕重复,并且dfs没法得到支路的图形,所以不行。Bfs吧,我还不太熟悉
,但是根据bfs的思路好像也会重复,并且感觉找到一种以后也不好退回。
那只能老老实实的枚举了。枚举以后用dfs判断。但是这道题如果真的是考试中,那我肯定做不出来,因为写的过程中总
是又疏忽的地方。看了答案再检查才发现错误。改完以后我就忘记是怎么错的了,现在想复现一下都忘了。以后一定要直

接记下来。

#include <iostream>
#include <string.h>
#include <cstdio>
using namespace std;
int d[4][5];
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
int used[4][5];
int sum=0;
int f;
int cnt;
void dfs(int x,int y){

    int i,nx,ny;
    if(cnt==5){
        f=1;
        sum++;
        return;
    }
    for(i=0;i<4;i++){
        nx=x+dx[i];
        ny=y+dy[i];
        if(nx>=1&&nx<=3&&ny>=1&&ny<=4&&d[nx][ny]==1&&!used[nx][ny]){
            used[nx][ny]=1;
            cnt++;
            dfs(nx,ny);
            //used[nx][ny]=0;
        }
        if(f)return;
    }
}
int main()
{
    int i,j,k,l,m;
    for(int i=1; i<=8; i++)
    {
        for(int j=i+1; j<=9; j++)
        {
            for(int k=j+1; k<=10; k++)
            {
                for(int l=k+1; l<=11; l++)
                {
                    for(int m=l+1; m<=12; m++)
                    {
                        memset(d,0,sizeof(d));
                        memset(used,0,sizeof(used));
                        f=0;
                        d[(i-1)/4+1][(i-1)%4+1]=1;//将数变为了二维的放进了数组,然后判断。
                        d[(j-1)/4+1][(j-1)%4+1]=1;//有点麻烦,我看有的是直接一维去判断。
                        d[(k-1)/4+1][(k-1)%4+1]=1;
                        d[(l-1)/4+1][(l-1)%4+1]=1;
                        d[(m-1)/4+1][(m-1)%4+1]=1;
                        for(int ii=1;ii<=3;ii++){
                            for(int jj=1;jj<=4;jj++){
                                printf("d[%d][%d]=%d ",ii,jj,d[ii][jj]);
                            }
                            cout<<endl;
                        }
                        used[(i-1)/4+1][(i-1)%4+1]=1;
                        cnt=1;
                        dfs((i-1)/4+1,(i-1)%4+1);
                        printf("s=%d\n",sum);
                    }
                }
            }
        }
    }
    cout<<sum<<endl;
    return 0;
}

第八题 四平方和

枚举一下,但是要注意时间的问题。我也是直接用三层循环,反向判断。O(n^3)的时间复杂度。应该是能过了。但是还有种
时间复杂度更低的方法。先将两个数字的和的情况全部枚举出来,放进一个数组,然后排序。最后两重循环二分查找是否再

数组中又n-a-b的值。但是太麻烦了,有简单的就用简单的。

#include <iostream>
#include <cstdio>
#include <cmath>
#define max 2300
using namespace std;

int main()
{
    int n,i,j,k,l;
    cin>>n;
    for(i=0; i<max; i++)
    {
        if(i*i<=n)
        for(j=0; j<max; j++)
        {
            if(i*i+j*j<=n)
            for(k=0; k<max; k++)
            {
                if(i*i+j*j+k*k>n)continue;
                int m=sqrt(n-i*i-j*j-k*k);
                if(i*i+j*j+k*k+m*m==n){
                    printf("%d %d %d %d\n",i,j,k,m);
                    return 0;
                }
            }
        }

    }
    return 0;
}

第九题 交换瓶子

看到这道题,我的第一想法是,检查,如果瓶子号和位置相等,除去。如果两个瓶子的号和位置正好互相一样,sum+1,然后
除去。最后剩下直接的k个,k-1次就可以互换完全。当时脑子一片混乱,就没想出来,害怕复杂度太高会超时,因为查的时候要两重循环。然后想想与其这样查,不如直接两重循环每回都把当前位置需要的换回来,发现也是ok的。但是估计真到考试这道题也是得不满的。这道题我花了许久时间。真到考试,可能第十题都没时间看了。
#include <iostream>
#include <cstdio>
using namespace std;
int a[1002],p[1002];
int main()
{
    int n,i,j,s=0;
    cin>>n;
    for(i=1;i<=n;i++){
        scanf("%d",&a[i]);
       // p[a[i]]=i;
       p[i]=i;//保存位置
    }
    for(i=1;i<=n;i++){
        if(a[i]!=p[i]){
            for(j=1;j<=n;j++){
                if(a[j]==p[i]){//找到和该位置号相同的瓶子
                    int t=a[j];//交换
                    a[i]=a[j];
                    a[j]=t;
                    s++;
                }
            }
        }

    }
    cout<<s<<endl;
    return 0;
}

我写的不太好,但是找到个厉害的。一重循环就搞定了。

#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
	int N,sum=0;
	int d[10010];
	int a[10010];
	int i,j,temp;
	scanf("%d",&N); 
	for(i=1;i<=N;i++)
	{
		cin>>a[i];//a是i位置的瓶子号
		d[a[i]]=i;//d是记录某个瓶子放在了多少位置,方便直接找,省去一重循环/
	}
	for(i=1;i<=N;i++)
	{
		if(d[i]!=i)
		{
			temp=a[i];
			a[i]=a[d[i]];//d[i]代表i这个瓶子放的位置。 这一点其实很不容易想,容易绕晕人。
			a[d[i]]=temp;
			d[temp]=d[i];
			d[i]=i;
			sum++;
		}
	}
	cout<<sum<<endl;
return 0;
}

第十题 最大比例

xi好tm大,必须用longlong了。数组也要开longlong的。这道题我的思路是直接把数组从小到大排列。然后找一个从第一项开始,往后如果和第一项不同了(记为第K项),则求他们的最小公约数g。然后第一项和第K项同时除以g。这个当作他们的比例。然后第K项开始,往后推,每个都乘这个比例。如果不满足,则退出,分子分母同时开根号。继续试。都满足了,得到答案。

但是问题就在,我在网上看到的题目中没有给出N的范围。并且没有蓝桥杯官网的vip,所以没法试验。但是给了3s,应该也许大概可能可以通过吧。我觉得思路应该没问题。结果应该是正确的。

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
ll a[102];
ll gcd(ll a,ll b){
    if(b==0)return a;
     else return gcd(b,a%b);
}
int main()
{
    int n,i;
    scanf("%d",&n);
    for(i=0;i<n;i++){
        scanf("%I64d",&a[i]);
    }
    sort(a,a+n);
    ll aa,bb,mm;
    for(i=1;i<n;i++){
        if(a[i]!=a[0]){
            ll t=gcd(a[i],a[0]);
            //printf("t=%I64d\n",t);
            aa=a[i]/t;
            bb=a[0]/t;
            break;
        }
    }
    printf("%I64d,%I64d\n",aa,bb);
    while(1){
        bool flag=true;
        for(int j=i+1;j<n;j++){
            mm=a[j-1];
            while(a[j]>mm){
                mm=mm*aa/bb;
                //printf("a[%d]=%I64d,mm=%I64d\n",j,a[j],mm);
            }
            printf("j=%d,mm=%I64d\n",j,mm);
            if(mm!=a[j]){
                flag=false;
                break;
            }
        }
        if(flag)break;
        else {
            printf("开根号\n");
            aa=sqrt(aa);
            bb=sqrt(bb);
        }
    }
    printf("%I64d,%I64d\n",aa,bb);
    return 0;
}

 

感想 

自己做题还考试是完全不一样的感觉,特别是我这种容易紧张的弱鸡,没准直接心态炸了。况且题是一年比一年难,所以我还是报b组吧。毕竟初入,头铁没有好下场,君不见三选奥巴马,五放加里奥。
觉得会和会是两码事,多练是真的。
写博客呢,是想记录一下,要不然都得忘了。
感觉写博客会让人进步= = 但是我懒...
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值