团体程序设计天梯赛-练习集L1-041~L1-050

文章目录

  • L1-041. 寻找250
  • L1-042. 日期格式化
  • L1-043 阅览室
  • L1-044. 稳赢
  • L1-045
  • L1-046. 整除光棍
  • L1-047. 装睡
  • L1-048. 矩阵A乘以B
  • L1-049
  • L1-050. 倒数第N个字符串

L1-041. 寻找250

团体程序设计天梯赛-练习集L1-041~L1-050_第1张图片

对方不想和你说话,并向你扔了一串数…… 而你必须从这一串数字中找到“250”这个高大上的感人数字。

输入格式:
输入在一行中给出不知道多少个绝对值不超过1000的整数,其中保证至少存在一个“250”。

输出格式:
在一行中输出第一次出现的“250”是对方扔过来的第几个数字(计数从1开始)。题目保证输出的数字在整型范围内。

输入样例:
888 666 123 -233 250 13 250 -222

输出样例:
5

Note:
骚年,在这么多对数字中找到你自己,其实还真不容易哈。这一题比较简单,但是提一个小知识点,当你用 %d 来输出一个字符时,输出的是它的 ASCII 值,但如果你用 %d 来接受它,它就强制转换成了数字了,当然这只适用于单个字符的情况。这一题不用考虑那么多,直接怼就是了。不要用字符串来接受,那样做会很麻烦,scanf 语句有空格识别的。你们可以注意到我的 count 是放在 while 的判断里的,这不是炫技,因为我试过单独列一个 count++,发现占用的运行内存比我现在的方法要大上几百 KB,这强迫症哪里能忍啊,果断改掉!

#include 

int main()
{
    int n, count = 0;
    while (++count) {            // count 放在 while 循环内,自增之后永远为增
        scanf("%d", &n);
        if (n == 250) {
            printf("%d", count);
            break;
        }
    }
    return 0;
}

读字符还是要读字符的,我不过写出来给你们参考一下而已(真香)。

#include 
#include 
#include 

int main()
{
    char ch;
    int count = 0, num = 0;
    ch = getchar();
    while (ch != '\n') {
        if(isdigit(ch)) {               // 求数字大小
            ch = ch -'0';
            num = num*10 + ch;
        }
        if (num == 250) {               // 找到250,输出计数,退出循环
            count ++;
            printf("%d", count);
            break;
        }
        if (ch == ' ') {
            // printf("num:%d count:%d\n", num, count);
            num = 0;                    // 遇见空格,重置 num 的值,同时计数加一
            count ++;
        }
        ch = getchar();                 // 读取下一个字符
    }
    return 0;
}

L1-042. 日期格式化

世界上不同国家有不同的写日期的习惯。比如美国人习惯写成“月-日-年”,而中国人习惯写成“年-月-日”。下面请你写个程序,自动把读入的美国格式的日期改写成中国习惯的日期。

输入格式:
输入在一行中按照“mm-dd-yyyy”的格式给出月、日、年。题目保证给出的日期是1900年元旦至今合法的日期。

输出格式:
在一行中按照“yyyy-mm-dd”的格式给出年、月、日。

输入样例:
03-15-2017

输出样例:
2017-03-15

Note:
之所以说 PTA 的题目好,是因为每一题看似都不难,但是想要最优是需要你去仔细思考的,本题就需要利用 scanf 函数的特性达到最优效果。

#include

int main()
{
    int a, b, c;
    scanf("%d-%d-%d", &a, &b, &c);
    printf("%d-%02d-%02d\n", c, a, b);
    return 0;
}

L1-043 阅览室

天梯图书阅览室请你编写一个简单的图书借阅统计程序。当读者借书时,管理员输入书号并按下S键,程序开始计时;当读者还书时,管理员输入书号并按下E键,程序结束计时。书号为不超过1000的正整数。当管理员将0作为书号输入时,表示一天工作结束,你的程序应输出当天的读者借书次数和平均阅读时间。

注意:
由于线路偶尔会有故障,可能出现不完整的纪录,即只有S没有E,或者只有E没有S的纪录,系统应能自动忽略这种无效纪录。另外,题目保证书号是书的唯一标识,同一本书在任何时间区间内只可能被一位读者借阅。

输入格式:
输入在第一行给出一个正整数N(≤10),随后给出N天的纪录。每天的纪录由若干次借阅操作组成,每次操作占一行,格式为:

书号([1, 1000]内的整数) 键值(S或E) 发生时间(hh:mm,其中hh是[0,23]内的整数,mm是[0, 59]内整数)

每一天的纪录保证按时间递增的顺序给出。

输出格式:
对每天的纪录,在一行中输出当天的读者借书次数和平均阅读时间(以分钟为单位的精确到个位的整数时间)。

输入样例:
3
1 S 08:10
2 S 08:35
1 E 10:00
2 E 13:16
0 S 17:00
0 S 17:00
3 E 08:10
1 S 08:20
2 S 09:00
1 E 09:20
0 E 17:00

输出样例:
2 196
0 0
1 60

Note:
本题有三个坑点,别问我我怎么知道的,我也是搜别人博客才知道的。。。第一个就是借阅时间只算最后一次借出到最早一次归还,第二个就是结果要四舍五入的输出。另外做题过程中自己发现的一些小问题,float 不能进行 ++ 操作,所以 count 要定义成 int 类型;四舍五入那里 int 要加括号。而且要注意这题有一个测试案例是有00:00借书的,即 time 的值为0所以我选择初始化数组的值为-1,但正常情况下谁会00:00来借书啊。。。算是一个 bug吧。

memset 是对较大的数组或结构体进行清零初始化的最快方法,因为它是直接对内存进行操作的。字符串数组就可以用 ‘\0’ 来初始化,虽然参数 c 要求是一个整数,但是整型和字符型是互通的。由于赋值为 ‘\0’ 和 0 是等价的,因此字符 ‘\0’ 在内存中就是 0。所以在 memset 中初始化为 0 也具有结束标志符 ‘\0’ 的作用,所以通常我们就写“0”。

#include 
#include 

int main()
{
    int N, num, count;
    float hh, mm, alltime, time[1000];
    char s[0];                                                      // 定义字符串数组来接收管理员的按键操作

    scanf("%d", &N);
    while (N--) {
        count = alltime = 0;                                        // 后一天,所有数据初始化
        memset(time, -1, sizeof(time));                             // 清空数组里的残余值,也算初始化
        while (1) {
            scanf("%d%s %f:%f", &num, s, &hh, &mm);                 // 字符串数组会忽视前面的空格
            if (num == 0) break;
            else if (s[0] == 'S')
                time[num] = hh*60 + mm;                             // 第二次借书的时间可以覆盖前一次
            else if (s[0] == 'E' && time[num] >= 0) {
                    alltime += (hh*60 + mm - time[num]);            // 借阅时间增加
                    count ++;                                       // 借出的书到换回来一个过程才算一次借阅
                    time[num] = -1;                                 // 置0标记已经归还过,不能更新归还时间
            }
        }

        if (count)
            printf("%d %d\n", count, (int)(alltime/count + 0.5));   // 输出结果,平均借阅时间四舍五入输出
        else
            printf("0 0\n");
    }
}

L1-044. 稳赢

大家应该都会玩“锤子剪刀布”的游戏:两人同时给出手势,胜负规则如图所示:
团体程序设计天梯赛-练习集L1-041~L1-050_第2张图片
现要求你编写一个稳赢不输的程序,根据对方的出招,给出对应的赢招。但是!为了不让对方输得太惨,你需要每隔K次就让一个平局。

输入格式:
输入首先在第一行给出正整数K(≤10),即平局间隔的次数。随后每行给出对方的一次出招:ChuiZi代表“锤子”、JianDao代表“剪刀”、Bu代表“布”。End代表输入结束,这一行不要作为出招处理。

输出格式:
对每一个输入的出招,按要求输出稳赢或平局的招式。每招占一行。

输入样例:
2
ChuiZi
JianDao
Bu
JianDao
Bu
ChuiZi
ChuiZi
End

输出样例:
Bu
ChuiZi
Bu
ChuiZi
JianDao
ChuiZi
Bu

Note:
间隔 n 次,则从一次平局到下一次平局需要加 n + 1。不能用 gets() 的原因在于 scanf 以回车或空格结束,然后将操作存入缓冲区,用 gets() 就会接收到结束符从而出错。也可以在 k 输入后加一个 getchar() 接受回车,然后后面全部用 get(s) 来接受字符串,也不会产生这种问题。

#include

int main()
{
    // 边读取字符串边输出结果,同时计数,计数到了输出一次平局,然后计数置0
    char s[8];
    int k, i = 0;                   // i 用于计数
    scanf("%d", &k);
    scanf("%s", s);                 // 不能用 gets(),否则会把回车读进去
    while (s[0] != 'E') {
        i ++;                       // i 至少为1,否则第一局就是平局
        if ((s[0] == 'B' && i%(k + 1) != 0) || (s[0] == 'J' && i%(k + 1) == 0)) printf("JianDao\n");
        if ((s[0] == 'J' && i%(k + 1) != 0) || (s[0] == 'C' && i%(k + 1) == 0)) printf("ChuiZi\n");
        if ((s[0] == 'C' && i%(k + 1) != 0) || (s[0] == 'B' && i%(k + 1) == 0)) printf("Bu\n");
        scanf("%s", s);             // 读取下一次出招
        if (i%(k + 1) == 0) i = 0;  // 到达间隔,计数置0
    }
    return 0;
}

L1-045


L1-046. 整除光棍

这里所谓的“光棍”,并不是指单身汪啦~ 说的是全部由1组成的数字,比如1、11、111、1111等。传说任何一个光棍都能被一个不以5结尾的奇数整除。比如,111111就可以被13整除。 现在,你的程序要读入一个整数x,这个整数一定是奇数并且不以5结尾。然后,经过计算,输出两个数字:第一个数字s,表示x乘以s是一个光棍,第二个数字n是这个光棍的位数。这样的解当然不是唯一的,题目要求你输出最小的解。

提示:
一个显然的办法是逐渐增加光棍的位数,直到可以整除x为止。但难点在于,s可能是个非常大的数 —— 比如,程序输入31,那么就输出3584229390681和15,因为31乘以3584229390681的结果是111111111111111,一共15个1。

输入格式:
输入在一行中给出一个不以5结尾的正奇数x(<1000)。

输出格式:
在一行中输出相应的最小的s和n,其间以1个空格分隔。

输入样例:
31

输出样例:
3584229390681 15

Note:
结果太大了,所以不可能正常的让机器去真计算,所以要写一个算法来模拟除法运算的过程。一开始我定义了一个很大字符数组来接收运算中的商,然后绞尽脑汁儿想了很久怎么把把商存入字符数组,脑袋痛就睡着了。梦中惊醒,我真是太 sd 了,我为什么要存入数组呀?直接输出不就行了吗。。。脑子抽的我真不适合学编程啊。而且题目中也没有暗示用字符数组来保存运算过程中的商,所以千万不要再像我一样动不动就字符数组了。。。第一个 while 循环那里,不要令 x >= s,因为输入的数 x 有可能本身就是一个光棍,此时商就是1,位数就是 x 的位数。但是因为 s 自增会变成 x 一样大,因为循环为真的原因还会自增一次,就导致结果错误了。

#include 

int main()
{
    int x, s = 0, n = 0;                            // s 记录余数,n 用来记录位数
    scanf("%d", &x);
    if (x%5 == 0 || x%2 == 0 || x >= 1000) return 0;// 无效输入退出程序

    while (x > s) {                                 // s 小于 x,则补1自增直到大于 x
        s = s*10 + 1;
        n ++;                                       // 同时位数自增
    }

    while(1) {
        printf("%d", s/x);                          // 计算商并输出
        s  = s%x;                                   // 令 s 等于余数
        if (s == 0) break;                          // 余数为0,退出循环
        s = s*10 + 1;                               // 除法的规则,s 只需要自增一位肯定大于 x
        n ++;                                       // 位数加一
    }
    printf(" %d", n);                               // 输出位数,别忘记空格
    return 0;
}

L1-047. 装睡

你永远叫不醒一个装睡的人 —— 但是通过分析一个人的呼吸频率和脉搏,你可以发现谁在装睡!医生告诉我们,正常人睡眠时的呼吸频率是每分钟15-20次,脉搏是每分钟50-70次。下面给定一系列人的呼吸频率与脉搏,请你找出他们中间有可能在装睡的人,即至少一项指标不在正常范围内的人。

输入格式:
输入在第一行给出一个正整数N(≤10)。随后N行,每行给出一个人的名字(仅由英文字母组成的、长度不超过3个字符的串)、其呼吸频率和脉搏(均为不超过100的正整数)。

输出格式:
按照输入顺序检查每个人,如果其至少一项指标不在正常范围内,则输出其名字,每个名字占一行。

输入样例:
4
Amy 15 70
Tom 14 60
Joe 18 50
Zoe 21 71

输出样例:
Tom
Zoe

Note:
唉我真是净挑些简单的题目做。。。没什么好记录的。

#include 
#include 

int main()
{
    int i, n, flag;
    char name[4];
    int br, pl;
    scanf("%d", &n);
    for (i = 0; i < n; i++) {
        flag = 0;
        scanf("%s %d %d", name, &br, &pl);
        if (br < 15 || br > 20) flag = 1;
        if (pl < 50 || pl > 70) flag = 1;
        if (flag) printf("%s\n", name);
        memset(name, '\0', sizeof(name));
    }
    return 0;
}

哈哈哈哈哈哈哈你要是不往下面看你就吃亏拉,其实这题更简单的做法是下面这样的,甚至都不要清空数组哈哈哈。直接用逆否做就行啦,我们知道呼吸15到20之间且脉搏50到70之间就不算睡觉,它的逆否就是非呼吸15到20之间或脉搏50到70之间。用该逆否做 if 的判断就可以啦。

#include 

int main()
{
    int i, n, br, pl;
    char name[4];
    scanf("%d", &n);
    for (i = 0; i < n; i++) {
        scanf("%s %d %d", name, &br, &pl);
        if (!(br <= 20 && br >= 15)||!(pl <= 70 && pl >= 50))
            printf("%s\n", name);
    }
    return 0;
}

L1-048. 矩阵A乘以B

给定两个矩阵A和B,要求你计算它们的乘积矩阵AB。需要注意的是,只有规模匹配的矩阵才可以相乘。即若A有R​a​​行、C​a​​列,B有R​b​​行、C​b​​列,则只有C​a​​与R​b​​相等时,两个矩阵才能相乘。

输入格式:
输入先后给出两个矩阵A和B。对于每个矩阵,首先在一行中给出其行数R和列数C,随后R行,每行给出C个整数,以1个空格分隔,且行首尾没有多余的空格。输入保证两个矩阵的R和C都是正数,并且所有整数的绝对值不超过100。

输出格式:
若输入的两个矩阵的规模是匹配的,则按照输入的格式输出乘积矩阵AB,否则输出Error: Ca != Rb,其中Ca是A的列数,Rb是B的行数。

输入样例1:
2 3
1 2 3
4 5 6
3 4
7 8 9 0
-1 -2 -3 -4
5 6 7 8

输出样例1:
2 4
20 22 24 16
53 58 63 28

输入样例2:
3 2
38 26
43 -5
0 17
3 2
-11 57
99 68
81 72

输出样例2:
Error: 2 != 3

Note:
做完之后一直有两个测试过不去,调试了很久发现二维数组用的 char 定义,用字符串习惯了。。。

#include 

int main()
{
    // 二维数组刚好可以表示矩阵,一维表示行号,二维表示列号,因此矩阵题目二维矩阵是最好的
    int ra, ca, rb, cb, i, j, k;            //定义 A,B 矩阵的行值列值
    int A[100][100], B[100][100], C[100][100] = {0};

    scanf("%d%d", &ra, &ca);                // 输入不一定非要空格的,scanf 能识别
    for (i = 0; i < ra; i++)
        for (j = 0; j < ca; j++)
            scanf("%d", &A[i][j]);

    scanf("%d%d", &rb, &cb);
    for (i = 0; i < rb; i++)
        for (j = 0; j < cb; j++)
            scanf("%d", &B[i][j]);

    if (ca != rb) {                         // 不能进行矩阵乘法
        printf("Error: %d != %d", ca, rb);
        return 0;
    }
    printf("%d %d\n", ra, cb);
    for (i = 0; i < ra; i++) {              // 先行
        for (j = 0; j < cb; j++) {          // 后列
            for (k = 0; k < ca; k++)        // 行列式乘法规律,中间数增到 ca - 1 为止
                C[i][j] += A[i][k]*B[k][j]; // 计算 C 的每一项
            printf("%d", C[i][j]);
            if (j + 1 != cb) printf(" ");   // 输出空格
        }
        if (i + 1 != ra) printf("\n");      // 换行
    }
    return 0;
}

L1-049


L1-050. 倒数第N个字符串

给定一个完全由小写英文字母组成的字符串等差递增序列,该序列中的每个字符串的长度固定为 L,从 L 个 a 开始,以 1 为步长递增。例如当 L 为 3 时,序列为 { aaa, aab, aac, …, aaz, aba, abb, …, abz, …, zzz }。这个序列的倒数第27个字符串就是 zyz。对于任意给定的 L,本题要求你给出对应序列倒数第 N 个字符串。

输入格式:
输入在一行中给出两个正整数 L(2 ≤ L ≤ 6)和 N(≤10​5​​)。

输出格式:
在一行中输出对应序列倒数第 N 个字符串。题目保证这个字符串是存在的。

输入样例:
3 7417

输出样例:
pat

Note:
直接令一个整型数据等于double类型数据的计算结果会丢失精读,不准确。在用 z 来表示偏移的字母时,理论上是偏移多少减多少。这一题要求的是倒数,比如那一位应该是 x,则 z 的 ASCII 值应该减去2,但实际上 x 是倒数第3位,所以在输入的 N 应该要处理完,即先减去1后才能得到正确的倒数位的字母。

#include 
#include 
double main()
{
    double L, N, n, yu, digit;
    scanf("%lf %lf", &L, &N);
    n = L - 1;                          // n 题目保证字符串是存在的
    N = N - 1;                          // 即 N 肯定是小于 pow(26, n),所以直接从 n - 1算

    while (1) {
        digit = floor(N/(pow(26, n)));  // 将整数商部分存入 digit,即为对应为的位置偏移,同时要向下取整
        char b = 'z';                   // 这里是将字符 b 赋值字符 z,写在表达式里的 'z' 是 z 的 ASCII 码值
        printf("%c", b - (int)digit);   // ASCII码的得转换是整型运算
        yu = pow(26, n);                // 如果在这里用 int 定义 yu 会丢失精度产生计算偏差
        N = (int)N%(int)yu;             // % 两边必须是整型变量
        n --;                           // 注意 n = 0 是要参与运算的,所以判定是 n 是否小于0
        if (n < 0) break;
    }
    return 0;
}

一定要自己写一遍哦~~~

你可能感兴趣的:(PTA,PTA,算法,团体程序设计天梯赛)