NOIP 提高組 初賽 四、閱讀程序寫結果 習題集(一)NOIP1998-NOIP1999

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。

錯誤有千百種,要做對本題,還是要跟着程序跑一跑,比較合理的思路是畫個表格進行數據跟蹤。如下:

i 1 2 3 4 5 6 7 8 9 10
a[i] 8 9 -1 24 6 5 11 15 -28 9
s 8 17 16 40 46 51 62 77 49 58
max 8 17 17 40 46 51 62 77 77 77
可以發現本題是找,從下標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

小細節沒有問題後,該題還有一定運算量,容易算錯,

用表格進行數據跟蹤:

i 2 3 4 5 6 7 8 9 10
co(i) 45 120 210 252 210 120 45 10 1
s 56 176 386 638 848 968 1013 1023 1024
答案: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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章