2013蓝桥杯预赛C/C++本科B组解题报告

来源:互联网 发布:php自定义表单源码 编辑:程序博客网 时间:2024/04/28 21:19

3
题目标题: 第39级台阶

    小明刚刚看完电影《第39级台阶》,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级!

    站在台阶前,他突然又想着一个问题:

    如果我每一步只能迈上1个或2个台阶。先迈左脚,然后左右交替,最后一步是迈右脚,也就是说一共要走偶数步。那么,上完39级台阶,有多少种不同的上法呢?


    请你利用计算机的优势,帮助小明寻找答案。

要求提交的是一个整数。
注意:不要提交解答过程,或其它的辅助说明文字。

 

解题思路:每次走一梯或者2梯,走到最后看步数,如果是奇数步,则是符合要求的,计数器加1即可!

答案:51167078

#include<stdio.h>int ans;void fun(int cur, int step){    if(cur<0)   return;    if(cur==0){        if(step%2==0)            ans++;        return;    }    fun(cur-1,step+1);    fun(cur-2,step+1);}int main(){    ans=0;    fun(39,0);    printf("%d\n",ans);    system("pause");    return 0;}/*51167078*/


8翻硬币


题目标题:翻硬币

    小明正在玩一个“翻硬币”的游戏。

    桌上放着排成一排的若干硬币。我们用 * 表示正面,用 o 表示反面(是小写字母,不是零)。

    比如,可能情形是:**oo***oooo
   
    如果同时翻转左边的两个硬币,则变为:oooo***oooo

    现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币,那么对特定的局面,最少要翻动多少次呢?
    我们约定:把翻动相邻的两个硬币叫做一步操作,那么要求:
  
程序输入:
两行等长的字符串,分别表示初始状态和要达到的目标状态。每行的长度<1000

程序输出:
一个整数,表示最小操作步数

例如:
用户输入:
**********
o****o****

程序应该输出:
5

再例如:
用户输入:
*o**o***o***
*o***o**o***

程序应该输出:
1

 


资源约定:
峰值内存消耗 < 64M
CPU消耗  < 1000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。

提交时,注意选择所期望的编译器类型。

题目分析:这个题咋一看比较复杂,当时简单分析了一下,就是从左往右对比两个字符串,一但发现不相同,就记录这个位置,连续记录两个位置之后,算一下这两个位置之间的距离,也就是将这一对不相等的硬币弄相等需要的步数(从某一头往另一头翻或者从中间往两头翻都一样,步数不变!),重复上述操作即可!当时想想应该是这样,没有系统分析为什么,后来看网上解释说是贪心,应该是这样的。

 

我还想说一下,好像搜索也行,不过数据有点大,效率有点低吧!

#include<stdio.h>#include<string.h>#define N 1100int fun(char *s1, char *s2){    int sum=0,i,x,y,step,len;    len=strlen(s1);    for(i=0,step=0;i<len;i++){        if(s1[i]!=s2[i]){            if(step==0)                x=i;            else                y=i;            step++;        }        if(step==2){            sum+=y-x;            step=0;        }    }    return sum;}int main() {    int ans=0;    char s1[N],s2[N];    scanf("%s%s",s1,s2);    ans=fun(s1,s2);    printf("%d\n",ans);    system("pause");    return 0;}


9带分数


标题:带分数

    100 可以表示为带分数的形式:100 = 3 + 69258 / 714

    还可以表示为:100 = 82 + 3546 / 197

    注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。

    类似这样的带分数,100 有 11 种表示法。

题目要求:
从标准输入读入一个正整数N (N<1000*1000)
程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
注意:不要求输出每个表示,只统计有多少表示法!


例如:
用户输入:
100
程序输出:
11

再例如:
用户输入:
105
程序输出:
6


资源约定:
峰值内存消耗 < 64M
CPU消耗  < 3000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。

提交时,注意选择所期望的编译器类型。


 

题目分析:暴力即可,回溯用于产生1-9的全排列,然后枚举两个位置i,j,这两个位置用于生产a,b,c三个数(1到i,i+1到j,j+1到9),枚举i,和j的时候加上一些剪枝即可!

代码:

#include<stdio.h>#include<string.h>int num[10],vis[10],n,ans;int getNum(int i,int j){    int k,sum=0;    for(k=i;k<=j;k++){        sum=sum*10+num[k];    }    return sum;}void check(){    int i,a,b,c,j;    for(i=1;i<=7;i++){        a=getNum(1,i);        if(a>n) break;//已经超出,后面不用再计算                for(j=i+1;j<=8;j++){            b=getNum(i+1,j);            c=getNum(j+1,9);            if(a+b/c>n) break;//因为位置是从前往后枚举的,所以一旦超出,后面全部超出,不用再算!                                  if(b%c==0&&n==a+b/c)                ans++;         }    }}void fun(int cur){    int i;    if(cur==10){        check();        return;    }    for(i=1;i<=9;i++){        if(vis[i]==0){            vis[i]=1;            num[cur]=i;            fun(cur+1);            vis[i]=0;        }        else continue;    }}int main(){    scanf("%d",&n);    ans=0;    memset(vis,0,sizeof(vis));    fun(1);    printf("%d\n",ans);    //system("pause");    return 0;}


10连号区间数


标题:连号区间数

    小明这些天一直在思考这样一个奇怪而有趣的问题:

    在1~N的某个全排列中有多少个连号区间呢?这里所说的连号区间的定义是:

    如果区间[L, R] 里的所有元素(即此排列的第L个到第R个元素)递增排序后能得到一个长度为R-L+1的“连续”数列,则称这个区间连号区间。

    当N很小的时候,小明可以很快地算出答案,但是当N变大的时候,问题就不是那么简单了,现在小明需要你的帮助。

输入格式:
第一行是一个正整数N (1 <= N <= 50000), 表示全排列的规模。
第二行是N个不同的数字Pi(1 <= Pi <= N), 表示这N个数字的某一全排列。

输出格式:
输出一个整数,表示不同连号区间的数目。

示例:
用户输入:
4
3 2 4 1

程序应输出:
7

用户输入:
5
3 4 2 5 1

程序应输出:
9

解释:
第一个用例中,有7个连号区间分别是:[1,1], [1,2], [1,3], [1,4], [2,2], [3,3], [4,4]
第二个用例中,有9个连号区间分别是:[1,1], [1,2], [1,3], [1,4], [1,5], [2,2], [3,3], [4,4], [5,5]


资源约定:
峰值内存消耗 < 64M
CPU消耗  < 5000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。

提交时,注意选择所期望的编译器类型。

 

题目分析:如果某个区间是连续区间,则区间最大值max和最小值min,则有max-min+1=区间长度,利用这个判断每个区间即可,我们只需要枚举出每个区间然后判断即可!

思路一:直接计算。

#include<stdio.h>#include<string.h>#include<stdlib.h>#define N 5100int a[N];int search(int n){    int i,j,sum=n,min,max,k;    for(i=0;i<n;i++){        for(j=i+1;j<n;j++){            min=0x7FFFFFFF;max=-0x7FFFFFFF;            for(k=i;k<=j;k++){                if(a[k]>max)                    max=a[k];            }            for(k=i;k<=j;k++){                if(a[k]<min)                    min=a[k];            }            if(max-min==j-i)                sum++;        }    }    return sum;}int main(){    int n,i,ans;    scanf("%d",&n);    for(i=0;i<n;i++){        scanf("%d",&a[i]);//a[i]=i+1;    }    ans=search(n);    printf("%d\n",ans);    return 0;}


 其实上面的代码时三重循环,效率很低,我们可以经过简单的优化变为二重循环,如下:

#include<stdio.h>   #include<stdlib.h>   int main(){      int i,j,k,max,min,count=0,n;      int a[50002];      scanf("%d",&n);      for(i=1;i<=n;i++)          //scanf("%d",&a[i]);         a[i]=i;     for(i=1;i<=n;i++){          max=a[i];min=a[i];          for(j=i+1;j<=n;j++){                if(a[j]>max)                  max=a[j];              if(a[j]<min)                  min=a[j];              if((max-min)==(j-i))                  count++;          }      }      printf("%d\n",count+n);    system("pause");     return 0;  }