NOIP-2011-J1-真题解析

一、选择题

1、B,基础题,考察二进制运算
2、B,基础题,48+9=57
3、C,基础题,考察存储空间计算,8GB/2MB=8*1024/2=4096
4、C,基础题,计算机基础常识,摩尔定律
5、B,根据题意,7个顶点任选2个都恰好有一条边,则就是7选2的组合数,21
6、D,基础题,考察计算机硬件系统,CPU组成,寄存器
7、C,数据结构题,二叉树结点数计算,深度最少的时候必然是完全二叉树,深度为n的满二叉树叶子结点为 2 n − 1 2^{n-1} 2n1,2011最接近2048,即 2 11 2^{11} 211,所以n-1=11,n=12
8、B,算法题,考察插入排序的基本思路
9、C,基础题,考察进制转换,二进制转十六进制,每4位二进制转成1位16进制,100/4=25
10、C,基础题,考察计算机文件删除操作常识
11、B,数据结构题,考察BFS和队列的应用
12、A,算法题,考察空间复杂度概念
13、C,数据结构题,链表不能随机访问,只能顺序遍历一遍
14、C,基础题,信息学基础,主流技术应用常识,ABD都是有生物特征,C没有
15、C,数据结构题,考察哈夫曼树,根据哈夫曼算法,构建好哈夫曼树可得C
16、D,基础题,考察编程语言,汇编语言,汇编语言大量应用于较底层的开发应用,没有被淘汰
17、A,算法题,考察回溯算法的基本概念
18、A,基础题,计算机历史常识
19、A,数据结构题,考察图的连通性,依次枚举每个选项即可,寻找每个边是否有其他路径可以替代,只有a边是有可替代的路径
20、C,基础题,考察计算机历史,冯诺依曼的计算机体系结构核心内容,采用存储程序和程序控制原理

二、问题求解

1、数学题,所有的序列里,1的个数要么是偶数,要么是奇数,所以各占一半,所以是8的全排列除以2,128个

2、编辑距离可以用动态规划算法来做,但是本题给出的序列比较简单,可以直接观察得到,1,删除A得到BCDEFG
2、C替换为A得到BADEFG
3、F替换为C得到BADECG
总共3步

三、阅读程序

1、

#include<iostream>
using namespace std;

int main()
{
    int i,n,m,ans;
    cin>>n>>m;
    i=n;
    ans=0;
    while(i<=m){
       ans+=i;
       i++;
    }
    cout<<ans<<endl;
    return 0;
}

输入:10 20
简单编程题,考察while循环语句,代码的功能是计算从10累加到20的和,结果是165

2、

#include<iostream>
#include<string>
using namespace std;

int main()
{
    string map= "2223334445556667778889999";
    string tel;
    int i;
    cin>>tel;
    for(i=0;i<tel.length();i++)
       if((tel[i]>='0') && (tel[i]<='9') )
           cout<<tel[i];
       else if( (tel[i]>='A') && (tel[i]<='Z'))
           cout<<map[tel[i]-'A'];
    cout<<endl;
    return 0;
}

输入:CCF-NOIP-2011
简单编程题,考察字符串遍历和处理,结果为:22366472011

3、

#include<iostream>
#include<cstring>
using namespace std;

const int SIZE = 100;

int main()
{
    int n,i,sum,x,a[SIZE];

    cin>>n;
    memset(a,0,sizeof(a));

    for(i=1;i<=n;i++){
        cin>>x;
        a[x]++;
    }
    i=0;
    sum=0;
    while(sum<(n/2+1)){
        i++;
        sum+=a[i];
    }
    cout<<i<<endl;
    return 0;
}

输入:
11
4 5 6 6 4 3 3 2 3 2 1
编程题,打表可得输出i为3
在这里插入图片描述
4、

#include<iostream>
using namespace std;

int solve(int n,int m)
{
    int i,sum;
    if(m==1) return 1;
    sum=0;
    for(i=1;i<n;i++)
       sum+= solve(i,m-1);
    return sum;
}

int main()
{
    int n,m;
    cin>>n>>m;
    cout<<solve(n,m)<<endl;
    return 0;
}

输入:7 4

递归求解题,阅读solve函数的递归逻辑,可得m=1时,返回1,否则solve(n,m)的值等于solve(1,m-1)+solve(2,m-1)+…+solve(n-1,m-1),如果打表可得结果20
在这里插入图片描述

四、完善程序

1、(子矩阵)给输入一个n1m1的矩阵a,和n2m2的矩阵b,问a中是否存在子矩阵和b相等。若存在,输出所有子矩阵左上角的坐标:若不存在输出“There is no answer”。

#include<iostream>
using namespace std;

const int SIZE = 50;

int n1,m1,n2,m2,a[SIZE][SIZE],b[SIZE][SIZE];


int main()
{
    int i,j,k1,k2;
    bool good ,haveAns;

    cin>>n1>>m1;
    for(i=1;i<=n1;i++)
       for(j=1;j<=m1;j++)
          cin>>a[i][j];

    cin>>n2>>m2;
    for(i=1;i<=n2;i++)
       for(j=1;j<=m2;j++)
           [];

    haveAns=false;
    for(i=1;i<=n1-n2+1;i++)
       for(j=1;j<= [];j++){
            [];
           for(k1=1;k1<=n2;k1++)
               for(k2=1;k2<=[] ;k2++){
                  if(a[i+k1-1][j+k2-1]!=b[k1][k2])
                     good=false;
               }
          if(good){
             cout<<i<<' '<<j<<endl;
             [];
          }
       }
    if(!haveAns)
       cout<<"There is no answer"<<endl;

    return 0;
}

若a当中存在与b相等的子矩阵,则如图所示,a中的与b相等的子矩阵的左上角坐标只能在绿色矩阵区域内移动,所以遍历该区域内的每一个坐标,判断以其为左上角坐标的尺寸与b相等的子矩阵是否与b相等。
①cin>>b[i][j]
②m1-m2+1,绿色区域的宽度
③good=true,设置good初值
④m2,比较子矩阵的每一个元素是否与b对应的元素相等
⑤hasAns=true,找到一个子矩阵与b相等
在这里插入图片描述

2、(大整数开方) 输入一个正整数n(1≤n≤10^100),试用二分法计算它的平方根的整数部分。

#include<iostream>
#include<string>
using namespace std;

const int SIZE=200;
struct hugeint{
    int len,num[SIZE];
};
//其中len表示大整数的位数;num[1]表示个位,num[2]表示十位,以此类推

hugeint times(hugeint a,hugeint b)
// 计算大整数a和b的乘积
{
    int i,j;
    hugeint ans;
    memset(ans.num,0,sizeof(ans.num));
    for(i=1;i<=a.len;i++)
       for(j=1;j<=b.len;j++)
            [] +=a.num[i]*b.num[j];  
    for(i=1;i<=a.len+b.len;i++){
        ans.num[i+1]+=ans.num[i]/10;
        []; 
    }
    if(ans.num[a.len+b.len]>0)
        ans.len=a.len+b.len;
    else
        ans.len=a.len+b.len-1;
    return ans;
}

hugeint add(hugeint a,hugeint b)
//计算大整数a和b 的和
{
    int i;
    hugeint ans;
    memset(ans.num,0,sizeof(ans.num));
    if(a.len>b.len)
        ans.len=a.len;
    else
        ans.len=b.len;
    for(i=1;i<=ans.len;i++){
        ans.num[i]+= [] ; 
        ans.num[i+1]+= ans.num[i]/10;
        ans.num[i]%=10;
    }
    if(ans.num[ans.len+1]>0)
        ans.len++;
    return ans;
}

hugeint average(hugeint a,hugeint b)
//计算大整数a和b的平均数的整数部分
{
    int i;
    hugeint ans;
    ans=add(a,b);
    for(i=ans.len;i>=2;i--){
        ans.num[i-1]+=([])*10; 

        ans.num[i]/=2;
    }
    ans.num[1]/=2;
    if(ans.num[ans.len]==0)
        ans.len--;
    return ans;
}

hugeint plustwo(hugeint a)
// 计算大整数a加2之后的结果
{
    int i;
    hugeint ans;
    ans=a;
    ans.num[1]+=2;
    i=1;
    while( (i<=ans.len)&&(ans.num[i]>=10) ){
        ans.num[i+1]+=ans.num[i]/10;
        ans.num[i]%=10;
        i++;
    }
    if(ans.num[ans.len+1]>0)
        []; 
    return ans;
}

bool over(hugeint a,hugeint b)
// 若大整数a>b则返回true,否则返回false
{
    int i;
    if([])  
        return false;
    if( a.len>b.len )
        return true;
    for(i=a.len;i>=1;i--){
        if(a.num[i]<b.num[i])
           return false;
        if(a.num[i]>b.num[i])
           return true;
    }
    return false;
}

int main()
{
    string s;
    int i;
    hugeint target,left,middle,right;
    cin>>s;
    memset(target.num,0,sizeof(target.num));
    target.len=s.length();
    for(i=1;i<=target.len;i++)
        target.num[i]=s[target.len-i]-[];
    memset(left.num,0,sizeof(left.num));
    left.len=1;
    left.num[1]=1;
    right=target;
    do{
        middle=average(left,right);
        if(over([]))
            right=middle;
        else
            left=middle;
    }while(!over(plustwo(left),right) );
    for(i=left.len;i>=1;i--)
       cout<<left.num[i];
    return 0;
}

在这里插入图片描述

高精度运算的应用,代码较长,函数较多,阅读后发现都是高精度运算常用的函数,比如乘法,加法等。
① ans.num[i+j-1],高精度乘法结果数组的下标
② ans.num[i]%=10,低位向高位进位,低位取余数
高精度加法,按位相加
③ a.num[i]+b.num[i]
高精度除以低精度,这里是除以常数2
④ ans.num[i]%2
高精度加低精度
⑤ ans.len++,最高位产生了新的进位,总长度加1
比较两个高精度数的大小
⑥ a.len<b.len, 先比较长度,如果长度小,值必然更小
⑦ '0’或48,将输入的字符串格式的数转换为高精度的字符数组存储方式,注意是逆序
然后使用二分法来逼近求解开方,每次取中点值,判断middle的平方是否大于原数,若大于,则表示取大了,需要在左边继续找,否则要在右边继续找
⑧ times(middle, middle), target

本题代码非常长,但难度其实更小,除了main函数里的7,8两个空,前面都是高精度运算的基本操作,答案都可以在对应的函数代码里找到现成的答案。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

严老师编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值