NOIP 提高组 初赛 四、阅读程序写结果 习题集(一)NOIP1998-NOIP1999

来源:互联网 发布:巴基斯坦 知乎 编辑:程序博客网 时间:2024/05/16 15:31

NOIP 提高组 初赛 四、阅读程序写结果 习题集(一)NOIP1998-NOIP1999

1.第四届(NOIP1998)

问题(原文是pascal,按题意,本人改写成C,C++版本):

1.

//1998.3.1
#include <stdio.h>

int main(){
    int i,s,max;
    int a[11];
    for(i=1;i<=10;i++)
        scanf("%d",&a[i]);
    max=a[1];
    s=a[1];
    for(i=2;i<=10;i++){
        if(s<0)
            s=0;
        s+=a[i];
        if(s>max)
            max=s;
    }
    printf("max=%d\n",max);
    return 0;
}
//输入:8 9 -1 24 6 5 11 15 -28 9
//输出:max= 

2.

//1998.3.2
#include <stdio.h>

const int n=10;

int co(int i1){
    int j1,s1;
    s1=n;
    for(j1=n-1;j1>=n-i1+1;j1--)
        s1=s1*j1/(n-j1+1);
    return s1;
}
 
int main(){
    int s,i;
    s=n+1;
    for(i=2;i<=n;i++)
        s+=co(i);
    printf("s=%d\n",s);
    return 0;
}

3.

//1998.3.3
#include <stdio.h>

int main(){
    int i,j,s;
    int b[6];
    s=1;
    for(i=1;i<=5;i++)
        b[i]=i;
    j=1;
    while(j>0){
        j=5;
        while(j>0&&b[j]==10+j-5)
            j--;
        printf("j=%d\n",j);
        if(j>0){
            s++;
            b[j]++;
            for(i=j+1;i<=5;i++)
                b[i]=b[j]+i-j;
        }
    }
    printf("s=%d\n",s);
    return 0;
}

4.
//1998.3.4
#include <stdio.h>

const int n=4;
int main(){
    int i,j,i1,j1,k,s,t,s1,L,swap;
    char temp;
    char a[n*2];
    scanf("%s",a);
    s=0;
    t=0;
    for(i=0;i<n*2;i++)
        if(a[i]=='1')
            s++;
        else if(a[i]=='0')
            t++;
    if(s!=n||t!=n)
        printf("error\n");
    else{
        s1=0;
        for(i=0;i<2*n-1;i++)
            if(a[i]!=a[i+1])
                s1++;
        printf("jamp=%d ",s1);
        swap=0;
        for(i=0;i<2*n-1;i++)
            for(j=i+1;j<2*n;j++)
                if(a[i]!=a[j]){
                    temp=a[i];
                    a[i]=a[j];
                    a[j]=temp;
                    s=0;
                    for(L=0;L<2*n-1;L++)
                        if(a[L]!=a[L+1])
                            s++;
                    if(s>swap){
                        swap=s;
                        i1=i;
                        j1=j;
                    }
                    temp=a[i];
                    a[i]=a[j];
                    a[j]=temp;    
                }
        if(swap>0)
            printf("maxswap=%d i=%d j=%d\n",swap-s1,i1+1,j1+1);
    }
    return 0;
}
//输入:10101100
//输出: 


问题解答:

1.该题容易做错,比如猜可能是找出串中的最大值,24;可能是找出非负的连续串和最大值,61;可能是求整个串的和,87。

错误有千百种,要做对本题,还是要跟着程序跑一跑,比较合理的思路是画个表格进行数据跟踪。如下:

i12345678910a[i]89-124651115-289s8171640465162774958max8171740465162777777可以发现本题是找,从下标1开始的连续串中的最大和,77。

答案:max=77

如不用表格跟踪,臆想,本题容易出错,不简单。

2.该题容易眼花,请注意:for(j1=n-1;j1>=n-i1+1;j1--)
        s1=s1*j1/(n-j1+1);一个是n-i1+1,一个是n-j1+1

小细节没有问题后,该题还有一定运算量,容易算错,

用表格进行数据跟踪:

i2345678910co(i)4512021025221012045101s56176386638848968101310231024答案:s=1024

3.一直在while(j>0&&b[j]==10+j-5)有疑问,应该是第二次遇到了。重读代码的过程中,发现,还是卡在

while(j>0&&b[j]==10+j-5)
            j--;

上面。

跟踪程序:


费了比较大的劲,找到了规律,但算个数,心有余而力不足。

硬着头皮试了一下:


思考过程如上图所示,顺序A->B->C->D。

有无更快的计算方法,该程序有无经典原型。

答案:s=252

4.对if中前后都有

                    temp=a[i];
                    a[i]=a[j];
                    a[j]=temp;

抱有疑问,怀疑是自己代码敲得有问题,经反复确认后,代码没问题,开始对照输入数据,阅读代码。

发现,程序是先交换其中两个字符,之后统计该字符串前后数据不同的最多数量,记下对应的i,j值。

10101100

10101010

很明显i=5,j=6

答案:jamp=5 maxswap=2 i=6 j=7

难度评估:

1中等2中等3难4简单


第五届(NOIP1999)

问题(原文是pascal,按题意,本人改写成C,C++版本):

1.

//1999.3.1
#include <stdio.h>
int main(){
    int i,j,k;
    int a[101];
    for(i=0;i<=100;i++)
        a[i]=i;
    for(k=5;k>=2;k--){
        for(i=1;i<=100;i++)
            if(i%k==0)
                a[i]=0;
        for(i=1;i<=99;i++)
            for(j=1;j<=100-i;j++)
                if(a[j]>a[j+1]){
                    a[j]=a[j]+a[j+1];
                    a[j+1]=a[j]-a[j+1];
                    a[j]=a[j]-a[j+1];
                }
    }
    j=1;
    while(a[j]==0&&j<100)
        j++;
    for(i=j;i<=100;i++)
        a[0]=a[0]+a[i];
    printf("%d\n",a[0]);
    return 0;
}
//本题的运行结果是:

2.

//1999.3.2
//2、设数组a[1],a[2],…,a[N],已存入了数据,
//调用不同的排序程序,则数据比较的次数将会不同,
//试计算分别调用下列不同的排序过程的比较运算的次数。
//其中swap(i,j)表示a[i]与a[j]进行交换。
//(1)
void sort1(int n){
    int i,j;
    for(i=1;i<=n-1;i++)
        for(j=1;j<=n;j++)
            if(a[j]<a[i])
                swap(i,j);
}
//调用该过程的语句为sort1(n),比较运算的次数为:__________
//(2)
void sort2(int i,int n){
    int j;
    if(i==n)
        printf("%d",a[n]);
    else
        for(j=i+1;j<=n;j++){
            if(a[j]<a[i])
                swap(i,j);
            printf("%d",a[i]);
            sort2(i+1,n);
        }
}
//调用该过程的语句为sort2(1,n),比较运算的次数为:__________
//(3)
void sort3(int i,j){
    int m;
    if(i!=j){
        m=(i+j)/2;
        sort3(i,m);
        sort3(m+1,j);
        merge;//{ 假设合并的元素分别为P、G个,需要比较P+G次 }
    }
}
//调用该过程的语句为sort3(1,n),比较运算的次数为:__________

             


问题解答:

1.

在将pascal转成C、C++的过程中,一不小心,将

   j=1;
    while(a[j]==0&&j<100)
        j++;
    for(i=j;i<=100;i++)
        a[0]=a[0]+a[i];
    printf("%d\n",a[0]);
    return 0;

放入for(k=5;k>=2;k--){中,把题目做难了。


for(i=1;i<=99;i++)
            for(j=1;j<=100-i;j++)
                if(a[j]>a[j+1]){
                    a[j]=a[j]+a[j+1];
                    a[j+1]=a[j]-a[j+1];
                    a[j]=a[j]-a[j+1];
                }

意识到上述代码类似冒泡排序,但

a[j]=a[j]+a[j+1];
a[j+1]=a[j]-a[j+1];
a[j]=a[j]-a[j+1];

三句代码输出数据,顺着程序走一遍,才发现是交换。

故上述代码经过一段时间才确认是冒泡排序。

数据变化如图所示:


最后等差数列数据之和:

(1+96)*20/2=970

答案:970

该题要是思路不清晰,比较耗时。

2.

(1)

做(1)的时候没有任何问题:

for(i=1;i<=n-1;i++)
        for(j=1;j<=n;j++)//一开始对j=1还是j=i有疑惑,不过,准备了两个答案,后发现标准答案对应j=1

i=1      n

i=2      n

i=3      n

......

i=n-1  n

故总次数:

n*(n-1)


经编程验证该排序有些问题:

//1999.3.2.1
#include <stdio.h>

int a[10]={0,1,2,3,4,5,6,7,8,9};
int count=0;
void swap(int i,int j){
    int t;
    t=a[i];
    a[i]=a[j];
    a[j]=t;
}
void sort1(int n){
    int i,j;
    for(i=1;i<=n-1;i++)
        for(j=1;j<=n;j++){
            count++;
            if(a[j]<a[i])
                swap(i,j);
        }
}

int main(){
    int num;    
    int i;
//    scanf("%d",&num);
    num=9;
    sort1(num);
    for(i=1;i<=num;i++)
        printf("%d ",a[i]);
    printf("\ncount=%d\n",count);
    return 0;
}

输出为:8 7 6 5 4 3 2 1 9

count=72

正常程序

for(i=1;i<=n-1;i++)//改成for(i=1;i<=n;i++)
        for(j=1;j<=n;j++){

此小题结束。

(2)

做(2)的时候有疑问://试计算分别调用下列不同的排序过程的比较运算的次数。

比较运算指的是什么,按照自个运算过程与答案对照,才发现是指if(a[j]<a[i])执行一次,算一次。

题意理解容易遇到上述障碍。

程序是按递归来写的,很多人估计会心理有阴影,递归很难的啊。

n=1         0

n=2         1

n=3         4

n=4         15

很明显,给的答案n*(n-1)/2不正确,答案是多少???

(3)

看样子像归并排序,时间复杂度O(nlogn),但如何推导,暂不明。

答案:nlog2n+c

本题(2)如何解决???

等熟练了,再回来解决该题。2016-12-12 21:16

阅读全文
0 0