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 |
答案: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 |
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