蓝桥杯 C/C++ 大学A组 2016年省赛真题

本文为武大郑未的《蓝桥杯历届真题解析》学习笔记。
http://weike.lanqiao.cn/static//coursehuifang/LNZTC++A/content/%E7%AC%AC%E5%9B%9B%E8%8A%822016%E5%B9%B4%E7%9C%81%E8%B5%9B%E7%9C%9F%E9%A2%98%E8%AF%A6%E8%A7%A3.html?courseid=18&dayclassid=1100

1.网友的年龄

网友说:“我的年龄是两位数,我比我儿子大27岁,如果把我的年龄的两位数字交换位置,刚好就是我儿子的年龄。”
请问:网友的年龄一共有多少种可能?

考点:两位数数字的拆分

/*2016年省赛1 网友的年龄*/
#include 
using namespace std;

int main()
{
    int x,y,i,j,Count=0;
    for(x=27;x<100;x++){
        i=x%10;
        j=x/10;
        y=i*10+j;
        if(x-27==y){
            //cout<
            Count++;
        }
    }
    cout<<Count<<endl;
    return 0;
}

2.生日蜡烛

某人从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。现在算来,他一共吹熄了236根蜡烛。
请问:他从多少岁开始过生日party?

考点:等差数列求和(使用除法时需考虑是否有余数)
解法一:
利用等差数列求和公式:sum=(a1+an)n/2,

/*生日蜡烛*/
#include 
using namespace std;

int main()
{
    int i,j,age;
    bool flag;
    for(i=1;i<50;i++){
        for(j=i;;j++){
            if((i+j)*(j-i+1)==236*2){
                age=i;
                flag=true;
                break;
            }
            else if((i+j)*(j-i+1)>236*2){
                flag=false;
                break;
            }
        }
        if(flag==true)
            break;
    }
    cout<<age<<endl;

    return 0;
}

解法二:
利用等差数列求和公式:sum=na1+(n-1)n/2

/*生日蜡烛*/
#include 
using namespace std;

int main()
{
    int n,t,age;
    for(n=2;n<50;n++){
        t=(n-1)*n/2;
        if((236-t)%n==0){
            age=(236-t)/n;
            break;
        }
    }
    cout<<age<<endl;

    return 0;
}

解法三:

/*生日蜡烛*/
#include 
using namespace std;

int main()
{
    int i,j,age,sum=0;
    bool flag;
    for(i=1;i<50;i++){
        for(j=i;;j++){
            sum+=j;
            if(sum==236){
                flag=true;
                age=i;
                break;
            }
            else if(sum>236){
                flag=false;
                break;
            }
        }
        if(flag==true)
            break;
        else
            sum=0;
    }
    cout<<age<<endl;

    return 0;
}

3,方格填数
全排列
(另撰文)

4.快速排序

(填快速排序中缺少的代码)
考点:快速排序
快速排序时一种十分高效的算法,其思想是:先选一个“标尺”,用它把整个序列过一遍,以保证其左边的元素都不大于它,其右边的元素都不小于它。这样排序问题就被分割为两个子区间,再分别对两个子区间进行排序就可以了。

2013年B组的第6题
三部排序 快速排序的变体 单指针 双指针 三指针

#include 
#include 
using namespace std;

void swap(int a[],int i,int j)
{
    int t=a[i];
    a[i]=a[j];
    a[j]=t;
}

/*定义一个标尺,将小于标尺的元素放在左侧,将大于标尺的元素放在右侧*/
int partition(int a[],int p,int r)
{
    int i=p;
    int j=r+1;
    int x=a[p]; //左端点的值
    while(1){   //从左到右找大的,从右到左找小的,将小的和大的交换
        while(i<r && a[++i]<x);
        while(a[--j]>x);
        if(i>=j)
            break;
        swap(a,i,j);
    }
    swap(a,p,j); //将标尺的值存在第j位(此句为填空代码)
    return j;
}

void quicksort(int a[],int p,int r)
{
    if(p<r){
        int q=partition(a,p,r); //q代表标识的下标
        quicksort(a,p,q-1);
        quicksort(a,q+1,r);
    }
}

int main()
{
    int i;
    int a[]={5,13,6,24,2,8,19,27,6,12,1,17};
    int N=12;

    quicksort(a,0,N-1);
    for(i=0;i<N;i++)
        cout<<a[i]<<' ';
    cout<<endl;
    return 0;
}

5.消除尾一

(填写划线部分缺少的代码)
下面的代码把一个整数的二进制表示的最右边的连续的1全部变成0;
如果最后一位是0,则原数字保持不变。

考点:
1.将一个整数以二进制形式输出
2.消除二进制数中的1
14年B组和C组的树状数组,lowbit=x-x&(x-1) ,得到的是最后(低)的一个二进制1所代表的十进制。
本题:消除末尾连续的1,可+1,再相与。
(做减法,0变1,1变0;做加法,1变0,0变1)

/*消除尾一*/
#include 
#include 
using namespace std;

void f(int x)
{
    int i;
    /*一个int型的数据一般占4个bytes,有32bit*/
    /*实现将x以二进制的形式输出*/
    for(i=0;i<32;i++)
        cout<<((x>>(31-i))&1); //将x右移(31-i)位,再与上1,每次输出的是一个十进制值代表相与的结果
    cout<<"  ";
    x=x&(x+1); //填空处

    for(i=0;i<32;i++)
        printf("%d",(x>>(31-i))&1);
    cout<<endl;
}

int main()
{
    f(103);
    f(12);
    return 0;
}

附:
以二进制形式输出十进制x的步骤:
x=12
00000000 00000000 00000000 00001100

1.将该二进制数右移31位,得:
00000000 00000000 00000000 00000000
2.将该二进制数右移30位,得:
00000000 00000000 00000000 00000000
3.将该二进制数右移29位,得:
00000000 00000000 00000000 00000000
……
27.将该二进制数右移4位
00000000 00000000 00000000 00000000
28.将该二进制数右移3位
00000000 00000000 00000000 00000001
29.将该二进制数右移2位
00000000 00000000 00000000 00000011
30.将该二进制数右移1位
00000000 00000000 00000000 00000110
31.将该二进制数右移0位
00000000 00000000 00000000 00001100

将每次向右移位的结果与1相与,然后输出与运算后的十进制数,即为原数的二进制形式。

6.寒假作业

也是考察全排列问题,同3.方格填数放于同一篇文章中。

7.剪格子

也是考察全排列问题,同3.方格填数放于同一篇文章中。

8.四平方和

四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多4个正整数的平方和。
如果把0包括进去,就正好可以表示为4个数的平方和。

比如:
5 = 0^2 + 0^2 + 1^2 + 2^2
7 = 1^2 + 1^2 + 1^2 + 2^2
(^符号表示乘方的意思)

对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对4个数排序:
0 <= a <= b <= c <= d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法

程序输入为一个正整数N (N<5000000)
要求输出4个非负整数,按从小到大排序,中间用空格分开

例如,输入:
5
则程序应该输出:
0 0 1 2

再例如,输入:
12
则程序应该输出:
0 2 2 2

再例如,输入:
773535
则程序应该输出:
1 1 267 838

考点:
考察枚举,但若直接对a,b,c,d四个数从0到N进行枚举,程序很可能会运行超时。所以需对枚举进行优化。由于N的大小由输入决定,无法通过它来优化枚举,另一种思路是减少枚举的变量。例如,x=N-a2-b2,检查x是否是两个数的平方和,如果是,则符合题目要求。
用哈希来进行缓存,在C++哈希是可以用map来做的。

#include 
#include 
#include 
#include 
using namespace std;

int N;
map<int,int>cache;
int main()
{
    int i;
    
    cin>>N;
    int a,b,c,d;
    for(c=0;c*c<=N/2;c++){
        for(d=c;c*c+d*d<=N;d++){
            if(cache.find(c*c+d*d)==cache.end()) //如果找不到,再存
                cache[c*c+d*d]=c;
        }
    }
    for(a=0;a*a<=N/4;a++){
        for(b=0;a*a+b*b<=N;b++){
            if(cache.find(N-a*a-b*b)!=cache.end()){ //如果找到了
                int c=cache[N-a*a-b*b];
                int d=int(sqrt(N-a*a-b*b-c*c));
                cout<<a<<' '<<b<<' '<<c<<' '<<d<<endl;
                return 0;
            }
        }
    }
    return 0;
}

对我而言,这道题主要考察了map模块的使用,关于map模块,可参考这篇文章:
添加链接描述
令附一个map使用小案例:

#include 
#include 
using namespace std;

int main()
{
    int i;

    map<int,char>milk; //创建map对象milk,其中键为int型,值为char型
    milk[0]='a'; //插入0-‘a'的键值对
    for(i=1;i<5;i++){
        milk[i]=milk[i-1]+1;
        cout<<milk[i]<<' '; //输出键对应的值
    }
    cout<<endl;
    milk.insert(make_pair(5,'g'));  //插入键值对
    cout<<milk[5]<<endl;
    if(milk.find(7)==milk.end()){  //查找,若该键不存在
       milk[7]='L';
       cout<<milk[7];
       }
    return 0;
}

你可能感兴趣的:(蓝桥杯)