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