寒假集训——PAT(15分)

本文涵盖了一系列编程挑战,包括计算含8数字的数量、验证身份证号码、创建藏头诗、计算自然常数e的近似值、解决兔子繁衍问题、实现九宫格输入法、拿糖果游戏、打印特殊图形及统计个位数频率。挑战涉及字符串操作、数学计算、逻辑判断和图形绘制,适合初学者和进阶者练习。
摘要由CSDN通过智能技术生成

7-14 含8的数字的个数 (5 分)

       现代人对数字越来越讲究,都喜欢含有8的数字。现要你编程计算a至b之间的含有数字8的数的个数(比如181,88,8,28这些数都含有数字8,而21,45,49等没有含有数字8)。

输入格式:

在一行中输入两个正整数a和b,用一个空格隔开。0<a<=b<100000。

输出格式:

输出a和b之间含有8的数的个数。包括a和b。

输入样例:

1 30

输出样例:

3

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int solve(int n){
    int sum=0;
    for(int i=1;i<=n;i++){
        int a=i;
        while(a){
            if((a%10)==8){
                sum++;
                break;
            }t
            a/=10;
        }
    }
    return sum;
}
int main(){
    int n,m;
    cin>>n>>m;
    cout<<solve(m)-solve(n-1)<<endl;
}

 

7-5 查验身份证 (15 分)     为练习赛(一)的题

一个合法的身份证号码由17位地区、日期编号和顺序编号加1位校验码组成。校验码的计算规则如下:

首先对前17位数字加权求和,权重分配为:{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};然后将计算的和对11取模得到值Z;最后按照以下关系对应Z值与校验码M的值:

Z:0 1 2 3 4 5 6 7 8 9 10

M:1 0 X 9 8 7 6 5 4 3 2

现在给定一些身份证号码,请你验证校验码的有效性,并输出有问题的号码。

输入格式:

输入第一行给出正整数N(≤100)是输入的身份证号码的个数。随后N行,每行给出1个18位身份证号码。

输出格式:

按照输入的顺序每行输出1个有问题的身份证号码。这里并不检验前17位是否合理,只检查前17位是否全为数字且最后1位校验码计算准确。如果所有号码都正常,则输出All passed。

输入样例1:

4

320124198808240056

12010X198901011234

110108196711301866

37070419881216001X

输出样例1:

12010X198901011234

110108196711301866

37070419881216001X

输入样例2:

2

320124198808240056

110108196711301862

输出样例2:

All passed

 

思路:

1.用一维数组来储存各位数字的权重。

2.用字符数组来存储检验码。

3.输入ID计算前17位的SUM。

4.SUM % 11 得到 Z 然后进行最后校验码的比较。

5.匹配相等不输出,不相等输出,并把flag标记为1。

6.最后判断是否有输出。

 

AC代码

#include<iostream>
using namespace std;
int main()
{
    char num[20];
    int N,sum=0;
    int  a[17] = {7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
    char M[11] = { '1' ,'0' ,'X', '9' ,'8' ,'7' ,'6' ,'5' ,'4' ,'3' ,'2' };
    
    while(scanf("%d",&N)!=EOF)
    {     
        int t=N;
        int n=0;
        while(t--){
         scanf("%s",&num);
         int flag=0;
             for(int i=0;i<17;i++)
             {
                 if(!(num[i]>='0'&&num[i]<='9'))
                {
                   flag = 1;
                   break;
                 }
            }
          if(flag==0)
          {
            for(int i=0;i<17;i++)
            {
                for(int j=0;j<11;j++)
                {
                    if(num[i]=='0'+j)
                     {
                          sum=sum+j*a[i];
                          break;
                     }
                }
            }
               sum=sum%11;
        if(M[sum]==num[17])
            n++;
        else
            {
            for(int i=0;i<17;i++)
            {
            printf("%c",num[i]);
            }
            printf("%c\n",num[17]);
            }
        if(n==N)
        printf("All passed\n");
        }
    else if(flag==1)
    {
         for(int i=0;i<17;i++)
         {
             printf("%c",num[i]);
        }
        printf("%c\n",num[17]);
    }
        }//while
    }//while
    return 0;
}

一年后重新做的AC代码:

#include<bits/stdc++.h>
using namespace std;
int main() {
	int T;
	int cnt=0;
	bool flag=false;
	int b[20] = {7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
	char c[20] = {'1','0','X','9','8','7','6','5','4','3','2'};
	string s[200];
	cin>>T;
	while(T--) {
		string a;
		int ans = 0;
		cin >> a;
		for(int i=0;i<17;i++)
			ans += (a[i]-'0')*b[i];
		ans%=11;
		//cout<<"ans="<<ans<<endl;
		if(c[ans]!=a[17])
			s[cnt++]=a;
	}
	if(cnt==0)
		cout<<"All passed"<<endl;
	else {
		for(int i=0;i<cnt;i++)
			cout<<s[i]<<endl;
	}
	return 0;
}

 

 

 

7-8 一帮一 (15 分)

“一帮一学习小组”是中小学中常见的学习组织方式,老师把学习成绩靠前的学生跟学习成绩靠后的学生排在一组。本题就请你编写程序帮助老师自动完成这个分配工作,即在得到全班学生的排名后,在当前尚未分组的学生中,将名次最靠前的学生与名次最靠后的异性学生分为一组。

输入格式:

输入第一行给出正偶数N(≤50),即全班学生的人数。此后N行,按照名次从高到低的顺序给出每个学生的性别(0代表女生,1代表男生)和姓名(不超过8个英文字母的非空字符串),其间以1个空格分隔。这里保证本班男女比例是1:1,并且没有并列名次。

输出格式:

每行输出一组两个学生的姓名,其间以1个空格分隔。名次高的学生在前,名次低的学生在后。小组的输出顺序按照前面学生的名次从高到低排列。

输入样例:

8

0 Amy

1 Tom

1 Bill

0 Cindy

0 Maya

1 John

1 Jack

0 Linda

输出样例:

Amy Jack

Tom Linda

Bill Maya

Cindy John

 

思路:此题一看就是要构造函数,mmp,但是我没有考虑周到,忘记定义一个标记元素避免重复,所以一直做不对。

AC代码

#include<stdio.h>
struct Class
{
    char name[10];
    int sex;
    int flag;//标记避免重复
}stu[55];
int main(){
    int x,i,j;
    scanf("%d",&x);
    for(i=0;i<x;i++){
        scanf("%d %s",&stu[i].sex,&stu[i].name);
        stu[i].flag=0;
    }//输入性别和名字
    for(i=0;i<=x/2;i++){    
        for(j=x-1;j>=i;j--){
            if(stu[i].sex!=stu[j].sex&&stu[j].flag!=1){
                printf("%s %s",stu[i].name,stu[j].name);
                stu[j].flag=1;
                if(i!=(x/2)-1)
                printf("\n");
                break;
            }
        }
    }
    return 0;
}

 

 

7-8 藏头诗 (15 分)

本题要求编写一个解密藏头诗的程序。

输入格式:

输入为一首中文藏头诗,一共四句,每句一行。注意:一个汉字占两个字节。

输出格式:

取出每句的第一个汉字并连接在一起形成一个字符串并输出。同时在末尾输入一个换行符。

输入样例:

一叶轻舟向东流

帆稍轻握杨柳手

风纤碧波微起舞

顺水任从雅客流

输出样例:

一帆风顺

 

思路:此题需要注意的汉字为两个字节,而char类型只占一个字节,因此要开一个char的二维数组进行输入和输出

AC代码:

#include<stdio.h>
int main(){
    int i,j;
    char a[4][20],b[20];
    for(i=0;i<4;i++){
        scanf("%s",&a[i]);
        b[j++]=a[i][0];
        b[j++]=a[i][1];
    }
    b[j]='\0';
    printf("%s",b);
return 0;
}

 

 

7-7 求e的近似值 (15 分)

自然常数e可以用级数1+1/1!+1/2!+⋯+1/n!来近似计算。本题要求对给定的非负整数n,求该级数的前n项和。

输入格式:

输入第一行中给出非负整数n(≤1000)。

输出格式:

在一行中输出部分和的值,保留小数点后八位。

输入样例:

10

输出样例:

2.71828180

 

AC代码

#include <stdio.h>  
#include <math.h>
int main(){  
    int n,i,j;
    double e=1;
    double sum=1;
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        for(j=1;j<=i;j++) {
            sum=sum*j; //算阶乘   
        }
        e=e+1.0/sum;
        sum=1;        
    }
    printf("%.8f",e);
    return 0;  
}

 

 

7-10 兔子繁衍问题 (15 分)

一对兔子,从出生后第3个月起每个月都生一对兔子。小兔子长到第3个月后每个月又生一对兔子。假如兔子都不死,请问第1个月出生的一对兔子,至少需要繁衍到第几个月时兔子总数才可以达到N对?

输入格式:

输入在一行中给出一个不超过10000的正整数N。

输出格式:

在一行中输出兔子总数达到N最少需要的月数。

输入样例:

30

输出样例:

9

 

AC代码

#include<stdio.h>
int main(void){
    int N;
    scanf("%d",&N);
    if(N==1) printf("1");
    else{
        int i,x1,x2,x;
        x1=1,x2=1,x=0;
        for(i=2;x2<N;i++){
            x=x1+x2;
            x1=x2;
            x2=x;
    }
    printf("%d",i);    
    }
    return 0;
}


#include <stdio.h>
int main(){
    int a, b, temp, month;
    int N;
    scanf("%d", &N);
    a = 0;
    b = 1;
    month = 1;
    while(b<N){
        month++;
        temp = a;
        a = b;
        b = b + temp;
    }
    printf("%d\n", month);
    return 0;
}

 

 

7-9 九宫格输入法 (15 分)

假设有九宫格输入法键盘布局如下:

[ 1,.?! ] [ 2ABC ] [ 3DEF ]

[ 4GHI ] [ 5JKL ] [ 6MNO ]

[ 7PQRS ] [ 8TUV ] [ 9WXYZ ]

[ 0空 ]

注意:中括号[ ]仅为了表示键盘的分隔,不是输入字符。每个中括号中,位于首位的数字字符即是键盘的按键,按一下即可输入该数字字符。多次按同一个键,则输入的字符依次循环轮流,例如按两次3,则输入D;按5次7,则输入S;按6次2,则输入A。按键0的输入组合是0和空格字符,即按两次0输入空格。

你需要对于给定的按键组合,给出该组合对应的文本。

输入格式:

输入在一行中给出数个字符的按键组合(例如 999 表示按3次9),每个字符的按键组合之间用空格间隔,最后一个输入法组合之后以换行结束。输入数据至少包括一个字符的按键组合,且输入总长度不超过500个字符。

输出格式:

在一行中输出该按键组合对应的文本。

输入样例:

22 5555 22 666 00 88 888 7777 4444 666 44

输出样例:

ALAN TURING

 

思路:直接定义一个char[][]二维数组即可

AC代码:

#include<stdio.h>
#include<string.h>
char b[10][10]={"0 ","1,.?!","2ABC","3DEF","4GHI","5JKL","6MNO","7PQRS","8TUV","9WXYZ"};
int main(){
    char a[505];
    while(scanf("%s",a)!=EOF){
        int m=strlen(a)%strlen(b[a[0]-'0']);
        if(m==0)
        m=strlen(b[a[0]-'0']);
        printf("%c",b[a[0]-'0'][m-1]);
    }
    return 0;
}

 

 

7-6 拿糖果 (15 分)

Long long ago,a handsome boy whose name is HSP studied in JSU of information science and engineering. He is clever and always thinks of ways to make fun of others. Now,it is your turn.

HSP和他的女朋友ZM来到了商店,商店有n个糖果,标号依次为1,2,3....n,对应的价值为W1,W2,W3...Wn。现在HSP先拿走一个标号为a的糖果,标号小于a的糖果就被ZM收回去了,然后HSP只能在剩下的糖果中选一个标号为b的糖果,请问Wa-Wb的最大值是多少?

输入格式:

多组数据输入,每一组数据第一行输入一个数字 n(2<=n<=100000),接下来n行,每行输入一个wi表示第i个糖果的价值

(0<wi<=100000)

输出格式:

每组数据输出Wa-Wb的最大值

输入样例:

3

3 2 1

6

1 1 1 1 1 1

输出样例:

2

0

 

思路:这个题我只过了一半的分,直接用最大值减去最小值,做题的时候我考虑到若是最大值为最后一个糖果,那这种方法肯定不行。但是又想不到什么更完善的方法,只能这样先提交了,能过一部分就过一部份吧... 

   后来我又用了一个方法,用两个for循环,第二个for求最小值,然后用第一个减第二个,直到找到最大值,不过...超时了  所以肯定也pass了 连一半得分都莫得

      最后又get一个新的办法,倒着比较,先找最小值,然后在前面找最大值,时间复杂度就可以缩减

#include<stdio.h>
#include<iostream>
using namespace std;
int Min[100010],Max[100010];
int v[100010];
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        Min[n]=10000000;
        Max[0]=0;
        int a;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a);
            v[i]=a;
            Max[i]=max(Max[i-1],a);
        }//找到最大值
        
        Min[n-1]=v[n];
        
        for(int i=n-2;i>=1;i--)
        {
            Min[i]=min(Min[i+2],v[i+1]);//倒着找最小值
        }
        
        int ans=Max[1]-Min[1];
        
        for(int i=2;i<n;i++)
        {
            ans=max(ans,(Max[i]-Min[i]));
        }
        printf("%d\n",ans);
    }   
    return 0;
}

 

 

7-9 剥洋葱 (15 分)

布告,布告! 应老师要求,我们要做一道打印图形的题目,这是程序员最基本的能力。 那废话不多说,我们来说要求的图形 AAAAA ABBBA ABCBA ABBBA AAAAA 就是外到内,从A到Z。每一层都是一种字母,最里面的一层为一个,即最中心的一个。

输入格式:

一行,一个整数,即图形的层数

输出格式:

如上述图形

输入样例:

3

输出样例:

AAAAA

ABBBA

ABCBA

ABBBA

AAAAA

                                    

 

此题一开始我想的太简单了,以为输入五行五列即可,结果只得了两分。这道题好理解但真的不太容易转换成代码,即便我看了大佬们的博客,现在还是有点含糊,需要反复的去理解。好了,话不多说上思路。

 

思路:

先画一个n=7的图像:

        图一 

如图图像所示(默认的i代表行,j代表列):看图像可以发现,第i行与第7-i-1是等价的;第j列与第7-j-1l列是等价的额,所以处理图像的时候可以只处理如下的图像:

        图二

再观察该图像可以发现:所有的A均有一个特点,坐标中含有0;所有的B均有一个特点,坐标中含有1;所有的C中均含有一个特点,坐标中均含有2;D的坐标中均含有3;再利用这个特点控制输出的内容。

AC代码

#include<stdio.h>
int cmp(int x,int y){
    if(x>y){
        return y;
    }
    else{
        return x;
    }
}//观察规律—— 每一个坐标点的字母都是 x,y中较小的一个 ,故返回较小的那个值
int main(){
    char ch[26]={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
    int num,c,n,t,y;
    scanf("%d",&num);
    c=num*2-1;//判断输出的是几行几列
         for(int i=0;i<c;i++){//控制坐标点
         t=i;
        if(t>c/2){
            t=c-t-1;
        }
        for(int j=0;j<c;j++){
            y=j;
            if(y>c/2){
                y=c-y-1;
            }
            for(int n=0;n<num;n++){
                if(t==n||j==n){
                    n=cmp(t,y);
                    printf("%c",ch[n]);
                    break;    
                }
            }
            if(j==c-1){
                printf("\n");//一行输入完了需要换行
            }
        }
    }
    return 0;
}

 

PTA天梯赛练习集 L1-003 个位数统计 (15 分)

 

    给定一个 k 位整数 N=dk−110k−1+⋯+d1101+d0 (0≤di≤9, i=0,⋯,k−1, dk−1>0),请编写程序统计每种不同的个位数字出现的次数。例如:给定 N=100311,则有 2 个 0,3 个 1,和 1 个 3。

输入格式:

    每个输入包含 1 个测试用例,即一个不超过 1000 位的正整数 N。

输出格式:

    对 N 中每一种不同的个位数字,以 D:M 的格式在一行中输出该位数字 D 及其在 N 中出现的次数 M。要求按 D 的升序输出。

输入样例:

    100311

输出样例:

    0:2

    1:3

    3:1

 

 

思路:

 此题我的思路是先统计位数,最后按照常规思路编写  最后编译成功但不出现结果 唉

  然后我就看了大佬们的博客,发现一个很奈斯的方法!超赞!

  将数字转化为字符串 然后利用 str[i]!='\0'来判断是否结束,不用像我一样麻烦统计位数。

 

1在输入数字位数未知时,可以通过whlie循环不断取余提取单个数位上的数字,直至n=0

2通过数组存储0~9的出现次数并初始化为0

3数字每出现一次,对应数组值+1,循环完毕后输出即可

AC代码

#include<stdio.h>
int main()
{
    int num[10] = {0}, i;
    char str[1005];
    gets(str);
    for (i = 0; str[i]!='\0';i++)
    {
        num[str[i] - '0']++;
    }
    for (i = 0;i < 10;i++)
    {
        if (num[i]>0)
        {
            printf("%d:%d\n",i,num[i]);
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值