2010NOIP模拟测试与题解 下载本文

内容发布更新时间 : 2024/12/22 14:40:46星期一 下面是文章的全部内容请认真阅读。

1、有故障的打字机 ( typewrt.pas/c/cpp )

【问题描述】

一台打字机准备将1到10n那的数依次打出。在打印过程中,这台打字机出现了一个故障:数字“3”打不出来。因此,所有含有数字“3”的数都没有被正确地打出。试问没有被正确打出的数一共有多少个。 【输入文件】

输入文件typewrt.in的第一行是一个正整数n。( n<=1000 ) 【输出文件】

输出文件typewrt.out的第一行也是唯一的一行应输出从1到10n这些数中不能被正确打印的数的个数。

【输入样例】 2

【输出样例】 19

#include using namespace std; ifstream fin(\ofstream fout(\int a[1005],b[1005]; int alen,blen; int n;

void mup(int x) {int i,w=0;

for(i=1;i<=alen+1;i++) {a[i]=a[i]*x+w; w=a[i]/10; a[i]%=10; }

if(a[alen+1]>0) alen++; }

void jian() {int i,j;

for(i=blen;i>=1;i--) {b[i]-=a[i];

j=i;

while(b[j]<0) {b[j]+=10; b[++j]--;} }

while(b[blen]==0) blen--; }

int main() {int i; fin>>n;

memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); b[n+1]=1; a[1]=1; blen=n+1; alen=1; for(i=1;i<=n;i++) mup(9); jian();

for(i=blen;i>=1;i--) fout<

2、最大约数和

( maxsum.pas/c/cpp )

【问题描述】

选取和不超过S的若干个不同的正整数,使得所有数的约数(不含它本身)之和最大。 【输入文件】

输入文件maxsum.in输入一个正整数S。(S<=1000)

- 1 -

【输出文件】

输出文件maxsum.out仅一行包含一个整数,输出最大的约数之和。 【输入样例】 11 【输出样例】 9

【样例说明 (无需输出)】

取数字4和6,可以得到最大值(1+2)+(1+2+3)=9。 #include using namespace std;

ifstream fin(\ofstream fout(%unsigned int m[1001][1001]={0};

unsigned int sumgcd(unsigned int i) {

unsigned int j,sum=0; for(j=1;j<=i/2;j++) if(i%j==0)sum+=j; return sum; }

unsigned int mymax(unsigned int x,unsigned int y) {

if(x>y)return x; else return y; }

int main() {

unsigned int w[1001]={0}, v[1001]={0} ; unsigned int s,i,j; fin>>s;

fin.close();

for(i=1;i

v[i]=sumgcd(i); }

for(i=1;i<=s-1;i++) for(j=1;j<=s;j++)

if(j

else m[i][j]=mymax(m[i-1][j],m[i-1][j-w[i]]+v[i]); fout<

- 2 -

3、阶乘问题( Fac) (fac.pas/c/cpp )

【问题描述】

对于小于25000的自然数n,求阶乘n!,(n-1)!,(n-2)!...3!,2!,1!最右边的非零数之和。

例如:当n=5时,5!=120,最右边非零数为2;4!=24,最右边非零数为4;3!=6,最右边非零数为6;2!=2,最右边非零数为2;1!=1,最右边非零数为1,则其最右边的非零数之和为2+4+6+2+1=15。 【输入文件】 (fac.in)

一个自然数N(0

对应的N个阶乘数的最右边的非零数之和。 【样例输入】

5

【样例输出】 15

#include { using namespace std; y=c[j]*i+t; ifstream fin (\ c[j]=y000; ofstream fout (\ t=y/10000; main(){ } int c[10000]; if (t>0) int n,s,k,i,j,t,m,y; c[++k]=t; fin>>n; j=0; s=0; while (c[j]==0) j++; k=0; m=c[j]; c[k]=1; while (m==0) m/=10; s+=c[0]; s+=m; for (i=2;i<=n;i++) }

{ fout<

4、出栈序列统计 (stack.pas/c/cpp )

【问题描述】 栈是常用的一种数据结构,有n个元素在栈顶端一侧等待进栈,栈顶端另一侧是出栈序列。你已经知道栈的操作有两种:push和pop,前者是将一个元素进栈,后者是将栈顶元素弹出。现在要使用这两种操作,由一个操作序列可以得到一系列的输出序列。请你编程求出对于给定的n,计算并输出由操作数序列1,2,?,n,经过一系列操作可能得到的输出序列总数。 【输入】 【输出】 就一个数n(1≤n≤1000)。 一个数,即可能输出序列的总数目。 【样例】 stack.in stack.out 3 5

- 3 -

【算法分析】 先了解栈的两种基本操作,进栈push就是将元素放入栈顶,栈顶指针上移一位,等待进栈队列也上移一位,出栈pop是将栈顶元素弹出,同时栈顶指针下移一位。

#include } using namespace std; len=len+5; ifstream fin (\ while (c[len]==0) len--; ofstream fout (\ } int c[10000]; for (i=n;i>=2;i--) int n,i,j,k,ys,len; { int main(){ ys=0; fin>>n; for (j=len;j>=1;j--) for (i=0;i<=n;i++) c[i]=0; { c[1]=1;len=1; k=c[j]; for (i=2*n;i>=n+2;i--) c[j]=(k+ys*10)/i; { ys=(k+ys*10)%i; for (j=1;j<=len;j++) c[j]=c[j]*i; } for (j=1;j<=len+4;j++) while (c[len]==0) len--; { } c[j+1]=c[j+1]+c[j]/10; for (i=len;i>=1;i--) fout<

5、流感会结束吗 (flu.pas/c/cpp )

【问题描述】

学校一共有n个学生。这n个学生里一共有m对朋友关系。 在流感发作期,每个健康学生都要看望当天他生病的朋友(如果有的话),并在第二天被传染上疾病(除非他在免疫期内);

每个生病的学生在第二天都会痊愈,并在这一天具有免疫性。从第三天起,看望生病的朋友将再次使他染上流感。

初始时(第一天),只有一个学生患有流感。试问多少天后流感会自动结束。 【输入文件】

输入文件flu.in中第一行输入两个正整数n和m。(n,m<=100 000)

接下来m行每行两个正整数x,y,表示编号为x的学生和编号为y的学生是一对朋友。输入数据保证每一对朋友关系只描述一次。

最后一行输入一个正整数,代表初始时患有流感的学生的编号。 【输出文件】

输出文件kitty.out以一行的形式输出,如果流感永远不会结束,请输出-1,否则输出多少天后流感会结束。答案保证不超过2 000 000 000。 【样例输入】 4 4 1 2 2 3 3 4

- 4 -

2 4 1

【样例输出】 3

【样例说明】

第一天1号学生生病,2号学生访问他;

第二天2号学生生病,其它三个学生访问他,由于1号处于免疫期,未患流感; 第三天3、4号学生生病,2号学生访问他们。

第四天3、4号学生痊愈,流感结束。

#include using namespace std; int n,m,a[100000][2],b[100001],s,temp; int main() { freopen(\ freopen(\ int j,k; scanf(\ for(j=0;j

- 5 -

{ if(b[j]==1) { b[j]=-1;

continue; } if(b[j]==2) { temp=1; b[j]=1; continue; } if(b[j]==-1)

{ b[j]=0; continue; } } s++; if(temp==0) break; for(j=1;j<=n;j++) if(b[j]==2&&j!=b[0]) break; if(j<=n) {

printf(\ return 0; }

} printf(\ return 0; }