PAT乙级(41-60题)

1041 考试座位号 (15 分)

题目

每个 PAT 考生在参加考试时都会被分配两个座位号,一个是试机座位,一个是考试座位。正常情况下,考生在入场时先得到试机座位号码,入座进入试机状态后,系统会显示该考生的考试座位号码,考试时考生需要换到考试座位就座。但有些考生迟到了,试机已经结束,他们只能拿着领到的试机座位号码求助于你,从后台查出他们的考试座位号码。

输入格式:

输入第一行给出一个正整数 N(≤1000),随后 N 行,每行给出一个考生的信息:准考证号 试机座位号 考试座位号。其中准考证号由 14 位数字组成,座位从 1 到 N 编号。输入保证每个人的准考证号都不同,并且任何时候都不会把两个人分配到同一个座位上。

考生信息之后,给出一个正整数 M(≤N),随后一行中给出 M 个待查询的试机座位号码,以空格分隔。

输出格式:

对应每个需要查询的试机座位号码,在一行中输出对应考生的准考证号和考试座位号码,中间用 1 个空格分隔。

输入样例:

4
10120150912233 2 4
10120150912119 4 1
10120150912126 1 3
10120150912002 3 2
2
3 4

输出样例:

10120150912002 2
10120150912119 1

代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class Main {

    static class Info {
        String id;
        int num1;
        int num2;

        public Info(String id, int num1, int num2) {
            this.id = id;
            this.num1 = num1;
            this.num2 = num2;
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        int count = Integer.parseInt(bufferedReader.readLine());

        ArrayList<Info> infoArrayList = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            String[] params = bufferedReader.readLine().split(" ");
            Info info = new Info(params[0], Integer.parseInt(params[1]), Integer.parseInt(params[2]));
            infoArrayList.add(info);
        }

        int checkNum = Integer.parseInt(bufferedReader.readLine());
        String[] params = bufferedReader.readLine().split(" ");

        String out = "";
        for (int i = 0; i < checkNum; i++) {
            int check = Integer.parseInt(params[i]);
            for (int j = 0; j < infoArrayList.size(); j++) {
                Info info = infoArrayList.get(j);
                if (info.num1 == check) {
                    out += info.id + " " + info.num2 + "\n";
                }
            }
        }
        System.out.print(out);
    }
}

1042 字符统计 (20 分)

题目

请编写程序,找出一段给定文字中出现最频繁的那个英文字母。

输入格式:

输入在一行中给出一个长度不超过 1000 的字符串。字符串由 ASCII 码表中任意可见字符及空格组成,至少包含 1 个英文字母,以回车结束(回车不算在内)。

输出格式:

在一行中输出出现频率最高的那个英文字母及其出现次数,其间以空格分隔。如果有并列,则输出按字母序最小的那个字母。统计时不区分大小写,输出小写字母。

输入样例:

This is a simple TEST. There ARE numbers and other symbols 1&2&3...........

输出样例:

e 7

代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;

public class Main {

    static class Info implements Comparable<Info> {

        char ch;
        int num;

        public Info(char ch, int num) {
            super();
            this.ch = ch;
            this.num = num;
        }

        @Override
        public int compareTo(Info o) {
            // TODO Auto-generated method stub
            if (num > o.num) {
                return -1;
            } else if (num < o.num) {
                return 1;
            } else {
                return ch > o.ch ? 1 : -1;
            }
        }

    }

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));

        String data = bf.readLine();

        ArrayList<Info> arrayList = new ArrayList<Main.Info>();
        for (int i = 0; i < 26; i++) {
            arrayList.add(new Info((char) ('a' + i), 0));
        }
        for (int i = 0; i < data.length(); i++) {
            char ch = data.charAt(i);
            if (ch >= 'a' && ch <= 'z') {
                arrayList.get(ch - 'a').num++;
            }
            if (ch >= 'A' && ch <= 'Z') {
                arrayList.get(ch - 'A').num++;
            }
        }

        Collections.sort(arrayList);
        System.out.print(arrayList.get(0).ch + " " + arrayList.get(0).num);
    }
}

1043 输出PATest (20 分)

题目

给定一个长度不超过 104 的、仅由英文字母构成的字符串。请将字符重新调整顺序,按 PATestPATest.... 这样的顺序输出,并忽略其它字符。当然,六种字符的个数不一定是一样多的,若某种字符已经输出完,则余下的字符仍按 PATest 的顺序打印,直到所有字符都被输出。

输入格式:

输入在一行中给出一个长度不超过 104 的、仅由英文字母构成的非空字符串。

输出格式:

在一行中按题目要求输出排序后的字符串。题目保证输出非空。

输入样例:

redlesPayBestPATTopTeePHPereatitAPPT

输出样例:

PATestPATestPTetPTePePee

思路

创建长度为6的数组,分别存放PATest的字符的个数。最后根据每个字符的个数,循环打印出每个字符。

代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        String data = bf.readLine();
        String info = "PATest";

        //按PATTest的顺序存储了每个字符的个数
        int chData[] = new int[6];
        int chCount = 0;

        for (int i = 0; i < data.length(); i++) {
            char ch = data.charAt(i);
            if (ch == 'P' || ch == 'A' || ch == 'T' || ch == 'e' || ch == 's' || ch == 't') {
                chData[getLoc(ch)]++;
                chCount++;
            }
        }
        String out = "";
        for (int i = 0; i < chCount * 6; i++) {
            int index = i % 6;
            if (chData[index] == 0) continue;
            out += info.charAt(index);
            chData[index]--;
        }
        System.out.print(out);
    }

    private static int getLoc(char ch) {
        int loc = 0;
        switch (ch) {
            case 'P':loc=0;break;
            case 'A':loc=1;break;
            case 'T':loc=2;break;
            case 'e':loc=3;break;
            case 's':loc=4;break;
            case 't':loc=5;break;
        }
        return loc;
    }
}

1044 火星数字 (20 分)

题目

火星人是以 13 进制计数的:

  • 地球人的 0 被火星人称为 tret。
  • 地球人数字 1 到 12 的火星文分别为:jan, feb, mar, apr, may, jun, jly, aug, sep, oct, nov, dec。
  • 火星人将进位以后的 12 个高位数字分别称为:tam, hel, maa, huh, tou, kes, hei, elo, syy, lok, mer, jou。

例如地球人的数字 29 翻译成火星文就是 hel mar;而火星文 elo nov 对应地球数字 115。为了方便交流,请你编写程序实现地球和火星数字之间的互译。

输入格式:

输入第一行给出一个正整数 N(<100),随后 N 行,每行给出一个 [0, 169) 区间内的数字 —— 或者是地球文,或者是火星文。

输出格式:

对应输入的每一行,在一行中输出翻译后的另一种语言的数字。

输入样例:

4
29
5
elo nov
tam

输出样例:

hel mar
may
115
13

思路

  1. 用数组存储个位与进位的火星文。
  2. 数字转火星文,个位即以num%13为下标的值,进位即以num/13为下标的值。
  3. 火星文转数字,遍历进位与个位的数组,得到相应的下标计算。
  4. 进位的个数比个位的个数少一个,可以把进位的第一个元素设置为空字符串。

代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

    final static String[] low = new String[]{"tret", "jan", "feb", "mar", "apr", "may", "jun", "jly", "aug", "sep", "oct", "nov", "dec"};
    final static String[] high = new String[]{"", "tam", "hel", "maa", "huh", "tou", "kes", "hei", "elo", "syy", "lok", "mer", "jou"};

    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(bf.readLine());

        String out = "";
        for (int i = 0; i < N; i++) {
            String str = bf.readLine();
            if (str.charAt(0) >= '0' && str.charAt(0) <= '9') {
                out += fun1(str) + "\n";
            } else {
                out += fun2(str) + "\n";
            }
        }
        System.out.print(out);
    }

    private static String fun1(String str) {
        int num = Integer.parseInt(str);
        String out = "";
        if (num / 13 != 0) out += high[num / 13];
        if ((num / 13 != 0) && (num % 13 != 0)) out += " ";
        if ((num % 13 != 0) || num == 0) out += low[num % 13];
        return out;
    }

    private static String fun2(String str) {
        int num = 0;
        if (str.length() == 3) {
            for (int i = 0; i < 13; i++) {
                if (str.equals(high[i])) {
                    num = i * 13;
                }
            }
            for (int i = 0; i < 13; i++) {
                if (str.equals(low[i])) {
                    num = i;
                }
            }
        } else if (str.length() == 4) {
            num = 0;
        } else {
            int highNum = 0, lowNum = 0;
            String[] param = str.split(" ");
            for (int i = 0; i < 13; i++) {
                if (param[0].equals(high[i])) {
                    highNum = i * 13;
                }
                if (param[1].equals(low[i])) {
                    lowNum = i;
                }
            }
            num = highNum + lowNum;
        }
        return num + "";
    }
}

1045 快速排序 (25 分)

题目

著名的快速排序算法里有一个经典的划分过程:我们通常采用某种方法取一个元素作为主元,通过交换,把比主元小的元素放到它的左边,比主元大的元素放到它的右边。 给定划分后的 N 个互不相同的正整数的排列,请问有多少个元素可能是划分前选取的主元?

例如给定 , 排列是1、3、2、4、5。则:

  • 1 的左边没有元素,右边的元素都比它大,所以它可能是主元;
  • 尽管 3 的左边元素都比它小,但其右边的 2 比它小,所以它不能是主元;
  • 尽管 2 的右边元素都比它大,但其左边的 3 比它大,所以它不能是主元;
  • 类似原因,4 和 5 都可能是主元。

因此,有 3 个元素可能是主元。

输入格式:

输入在第 1 行中给出一个正整数 N(≤105); 第 2 行是空格分隔的 N 个不同的正整数,每个数不超过 109

输出格式:

在第 1 行中输出有可能是主元的元素个数;在第 2 行中按递增顺序输出这些元素,其间以 1 个空格分隔,行首尾不得有多余空格。

输入样例:

5
1 3 2 4 5

输出样例:

3
1 4 5

思路

将读入的数组排序,若某个位置的元素,排序前与排序后位置不变,且左边的元素均小于该元素,该元素就是主元。

注意事项

  1. 暴力解法会超时。
  2. 当结果为0是,需要打印一个换行,否则显示格式错误。

代码

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int cmp(int a, int b) {
    return a < b;
}

int main() {
    int N;
    cin >> N;

    vector<int> v(N),sortV(N);

    cin.sync_with_stdio(false);
    for (int i = 0; i < N; i++) {
        int tmp;
        cin >> tmp;
        sortV[i] = v[i] = tmp;
    }

    sort(sortV.begin(), sortV.end(), cmp);

    vector<int> result;
    int max = 0;
    for (int i = 0; i < N; i++) {
        if (v[i] == sortV[i] && v[i] > max) {
            result.push_back(v[i]);
        }
        max = v[i] > max ? v[i] : max;
    }
    
    cout << result.size() << endl;
    if (result.size() == 0) {
        cout << endl;
        return 0;
    }
    sort(result.begin(), result.end(), cmp);
    for (int i = 0; i < result.size(); i++) {
        if (i == 0) {
            cout << result[i];
            continue;
        }
        cout << " " << result[i];
    }
}

1046 划拳 (15 分)

题目

划拳是古老中国酒文化的一个有趣的组成部分。酒桌上两人划拳的方法为:每人口中喊出一个数字,同时用手比划出一个数字。如果谁比划出的数字正好等于两人喊出的数字之和,谁就赢了,输家罚一杯酒。两人同赢或两人同输则继续下一轮,直到唯一的赢家出现。

下面给出甲、乙两人的划拳记录,请你统计他们最后分别喝了多少杯酒。

输入格式:

输入第一行先给出一个正整数 N(≤100),随后 N 行,每行给出一轮划拳的记录,格式为:

甲喊 甲划 乙喊 乙划

其中是喊出的数字,是划出的数字,均为不超过 100 的正整数(两只手一起划)。

输出格式:

在一行中先后输出甲、乙两人喝酒的杯数,其间以一个空格分隔。

输入样例:

5
8 10 9 12
5 10 5 10
3 8 5 12
12 18 1 13
4 16 12 15

输出样例:

1 2

代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        int count = Integer.parseInt(bufferedReader.readLine());

        int a = 0, b = 0;
        for (int i = 0; i < count; i++) {
            String[] params = bufferedReader.readLine().split(" ");

            int shout = Integer.parseInt(params[0]) + Integer.parseInt(params[2]);
            int aAct = Integer.parseInt(params[1]);
            int bAct = Integer.parseInt(params[3]);
            if ((aAct == shout && bAct == shout) || (aAct != shout && bAct != shout)) {
            } else if (aAct == shout) {
                b++;
            } else if (bAct == shout) {
                a++;
            }
        }

        System.out.print(a + " " + b);
    }
}

1047 编程团体赛 (20 分)

题目

编程团体赛的规则为:每个参赛队由若干队员组成;所有队员独立比赛;参赛队的成绩为所有队员的成绩和;成绩最高的队获胜。

现给定所有队员的比赛成绩,请你编写程序找出冠军队。

输入格式:

输入第一行给出一个正整数 N(≤104),即所有参赛队员总数。随后 N 行,每行给出一位队员的成绩,格式为:队伍编号-队员编号 成绩,其中队伍编号为 1 到 1000 的正整数,队员编号为 1 到 10 的正整数,成绩为 0 到 100 的整数。

输出格式:

在一行中输出冠军队的编号和总成绩,其间以一个空格分隔。注意:题目保证冠军队是唯一的。

输入样例:

6
3-10 99
11-5 87
102-1 0
102-3 100
11-9 89
3-2 61

输出样例:

11 176

代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(bf.readLine());

        int[] ID = new int[1001];
        for (int i = 0; i < N; i++) {
            String data = bf.readLine();

            int id = Integer.parseInt(data.split("-")[0]);
            int grade = Integer.parseInt(data.split(" ")[1]);

            ID[id] += grade;
        }

        int Max = 0;
        int No = 0;
        for (int i = 0; i < 1000; i++) {
            if (ID[i] > Max) {
                Max = ID[i];
                No = i;
            }
        }
        System.out.println(No + " " + Max);
    }
}

1048 数字加密 (20 分)

题目

本题要求实现一种数字加密方法。首先固定一个加密用正整数 A,对任一正整数 B,将其每 1 位数字与 A 的对应位置上的数字进行以下运算:对奇数位,对应位的数字相加后对 13 取余——这里用 J 代表 10、Q 代表 11、K 代表 12;对偶数位,用 B 的数字减去 A 的数字,若结果为负数,则再加 10。这里令个位为第 1 位。

输入格式:

输入在一行中依次给出 A 和 B,均为不超过 100 位的正整数,其间以空格分隔。

输出格式:

在一行中输出加密后的结果。

输入样例:

1234567 368782971

输出样例:

3695Q8118

注意事项

  1. 先对两数组进行reverse,会简化代码。
  2. 当B长度小于A长度时,需要在前面补上'0'。

代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String[] params = reader.readLine().split(" ");

        StringBuffer str1 = new StringBuffer(params[0]).reverse();
        StringBuffer str2 = new StringBuffer(params[1]).reverse();

        //B长度较A短时,需要在前面补上0.
        if (str2.length() < str1.length()) {
            int count = str1.length() - str2.length();
            for (int i = 0; i < count; i++) {
                str2.append('0');
            }
        }
        for (int i = 0; i < str2.length(); i++) {
            int b = str2.charAt(i) - '0';
            if (i >= str1.length()) break;
            int a = str1.charAt(i) - '0';

            //奇数位
            if ((i + 1) % 2 == 1) {
                int num = (a + b) % 13;
                str2.setCharAt(i, num == 12 ? 'K' : (num == 11 ? 'Q' : (num == 10 ? 'J' : ((char) (num + '0')))));
            } else {
                str2.setCharAt(i, (char) ((b - a < 0 ? b - a + 10 : b - a) + '0'));
            }
        }
        System.out.print(str2.reverse());
    }
}

1049 数列的片段和 (20 分)

题目

给定一个正数数列,我们可以从中截取任意的连续的几个数,称为片段。例如,给定数列 { 0.1, 0.2, 0.3, 0.4 },我们有 (0.1) (0.1, 0.2) (0.1, 0.2, 0.3) (0.1, 0.2, 0.3, 0.4) (0.2) (0.2, 0.3) (0.2, 0.3, 0.4) (0.3) (0.3, 0.4) (0.4) 这 10 个片段。

给定正整数数列,求出全部片段包含的所有的数之和。如本例中 10 个片段总和是 0.1 + 0.3 + 0.6 + 1.0 + 0.2 + 0.5 + 0.9 + 0.3 + 0.7 + 0.4 = 5.0。

输入格式:

输入第一行给出一个不超过 105 的正整数 N,表示数列中数的个数,第二行给出 N 个不超过 1.0 的正数,是数列中的数,其间以空格分隔。

输出格式:

在一行中输出该序列所有片段包含的数之和,精确到小数点后 2 位。

输入样例:

4
0.1 0.2 0.3 0.4

输出样例:

5.00

思路

如果用暴力解决会触发第3,4个测试点,导致超时。因此,需要分析序列的每个数字出现了多少次。以本题为例,序列0.1, 0.2, 0.3, 0.4出现的次数如下表所示。

0.1
0.1 0.2
0.1 0.2 0.3
0.1 0.2 0.3 0.4
0.2
0.2 0.3
0.2 0.3 0.4
0.3
0.3 0.4
0.4

可见规律如下:

元素 出现次数
0.1 4 = 1 × 4
0.2 6 = 2 × 3
0.3 6 = 3 × 2
0.4 4 = 4 × 1

即N个元素的序列中,元素data[i] 出现了:(N-i)×(i+1)次。

注意事项

  1. 用Java会超时,因此使用C++。
  2. 多次进行小数运算,需要用double保证精确。

代码

#include <iostream>

using namespace std;

int main() {
    int N;
    cin >> N;

    //cin.sync_with_stdio(false);
    double sum = 0;
    for (size_t i = 0; i < N; i++) {
        double tmp;
        cin >> tmp;
        sum += (i + 1)*(N - i)*tmp;
    }

    printf("%.2f", sum);
}

1050 螺旋矩阵 (25 分)

题目

本题要求将给定的 N 个正整数按非递增的顺序,填入“螺旋矩阵”。所谓“螺旋矩阵”,是指从左上角第 1 个格子开始,按顺时针螺旋方向填充。要求矩阵的规模为 m 行 n 列,满足条件:m×n 等于 N;m≥n;且 m−n 取所有可能值中的最小值。

输入格式:

输入在第 1 行中给出一个正整数 N,第 2 行给出 N 个待填充的正整数。所有数字不超过 104,相邻数字以空格分隔。

输出格式:

输出螺旋矩阵。每行 n 个数字,共 m 行。相邻数字以 1 个空格分隔,行末不得有多余空格。

输入样例:

12
37 76 20 98 76 42 53 95 60 81 58 93

输出样例:

98 95 93
42 37 81
53 20 76
58 60 76

思路

  1. 先对数据从大到小排序。
  2. 创建一个m*n的二维数组,初值为-1。
  3. 按照题目的逻辑,控制i、j游标的加减,实现左右上下的逆时针移动。边界条件:
    • i,j的值与m,n的值。
    • v[i][j]的值是否为-1。

注意事项

最后一个测试点可能超时,解决方法:

  1. 通过cin.sync_with_stdio(false)加速输入。
  2. 调用getOrder时使用引用传参。

代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>

using namespace std;

int cmp(int a, int b) {
    return a > b;
}

enum Order { RIGHT, DOWN, LEFT, UP };
Order getOrder(Order order, int i, int j, vector<vector<int>> &v);

int main() {
    int N;
    cin >> N;
    vector<int> originList(N);

    cin.sync_with_stdio(false);
    for (int i = 0; i < N; i++) {
        int tmp;
        cin >> tmp;
        originList[i] = tmp;
    }

    sort(originList.begin(), originList.end(), cmp);

    int m, n;
    for (int i = int(sqrt(N)); i >= 1; i--) {
        if (N%i == 0) {
            n = i;
            m = N / n;
            break;
        }
    }

    //创建一个m*n大小的二维数组,初始值为-1
    vector<vector<int>> v(m,vector<int>(n));
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            v[i][j] = -1;
        }
    }

    int i = 0, j = 0;
    int count = 0;
    Order order = RIGHT;

    while (count < originList.size()) {
        int num = originList[count++];
        v[i][j] = num;
        order = getOrder(order, i, j, v);
        //通过order控制i、j的值,实现控制方向切换。
        if (order == RIGHT || order == LEFT) {
            j += order == RIGHT ? 1 : -1;
        } else if (order == DOWN || order == UP) {
            i += order == DOWN ? 1 : -1;
        }
    }

    //打印输出
    for (int i = 0; i < v.size(); i++) {
        for (int j = 0; j < v[i].size(); j++) {
            if (j == 0) {
                cout << v[i][j];
            } else {
                cout << " " << v[i][j];
            }
        }
        cout << endl;
    }
}

Order getOrder(Order order, int i, int j, vector<vector<int>> &v) {
    Order newOrder = order;
    switch (order) {
    case RIGHT:
        if (j + 1 == v[0].size() || v[i][j + 1] != -1) {
            newOrder = DOWN;
        }
        break;
    case DOWN:
        if (i + 1 == v.size() || v[i + 1][j] != -1) {
            newOrder = LEFT;
        }
        break;
    case LEFT:
        if (j - 1 < 0 || v[i][j - 1] != -1) {
            newOrder = UP;
        }
        break;
    case UP:
        if (v[i - 1][j] != -1) {
            newOrder = RIGHT;
        }
        break;
    }
    return newOrder;
}

1051 复数乘法(15 分)

题目

复数可以写成 (A+Bi) 的常规形式,其中 A 是实部,B 是虚部,i 是虚数单位,满足 i​2​​=−1;也可以写成极坐标下的指数形式 (R×e​(Pi)​​),其中 R 是复数模,P 是辐角,i 是虚数单位,其等价于三角形式 (R(cos(P)+isin(P))。

现给定两个复数的 R 和 P,要求输出两数乘积的常规形式。

输入格式:

输入在一行中依次给出两个复数的 R​1​​, P​1​​, R​2​​, P​2​​,数字间以空格分隔。

输出格式:

在一行中按照 A+Bi 的格式输出两数乘积的常规形式,实部和虚部均保留 2 位小数。注意:如果 B 是负数,则应该写成 A-|B|i 的形式。

输入样例:

2.3 3.5 5.2 0.4

输出样例:

-8.68-8.23i

注意事项

  1. 结果小于0.01要值为零。
  2. 注意虚部的正负号输出。

代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.DecimalFormat;

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        String[] params = bufferedReader.readLine().split(" ");

        double R1 = Double.parseDouble(params[0]);
        double P1 = Double.parseDouble(params[1]);

        double R2 = Double.parseDouble(params[2]);
        double P2 = Double.parseDouble(params[3]);

        double R = R1 * Math.cos(P1) * R2 * Math.cos(P2) - R1 * Math.sin(P1) * R2 * Math.sin(P2);
        double P = R1 * Math.cos(P1) * R2 * Math.sin(P2) + R2 * Math.cos(P2) * R1 * Math.sin(P1);

        if(Math.abs(R)<0.01) {
            R = 0;
        }
        if(Math.abs(P)<0.01) {
            P = 0;
        }

        //%+表示数据带正负号
        System.out.printf("%.2f%+.2fi\n", R, P);
    }
}

1052 卖个萌 (20 分)

题目

萌萌哒表情符号通常由“手”、“眼”、“口”三个主要部分组成。简单起见,我们假设一个表情符号是按下列格式输出的:

[左手]([左眼][口][右眼])[右手]

现给出可选用的符号集合,请你按用户的要求输出表情。

输入格式:

输入首先在前三行顺序对应给出手、眼、口的可选符号集。每个符号括在一对方括号 []内。题目保证每个集合都至少有一个符号,并不超过 10 个符号;每个符号包含 1 到 4 个非空字符。

之后一行给出一个正整数 K,为用户请求的个数。随后 K 行,每行给出一个用户的符号选择,顺序为左手、左眼、口、右眼、右手——这里只给出符号在相应集合中的序号(从 1 开始),数字间以空格分隔。

输出格式:

对每个用户请求,在一行中输出生成的表情。若用户选择的序号不存在,则输出 Are you kidding me? @\/@

输入样例:

[╮][╭][o][~\][/~]  [<][>]
[╯][╰][^][-][=][>][<][@][⊙]
[Д][▽][_][ε][^]  ...
4
1 1 2 2 2
6 8 1 5 5
3 3 4 3 3
2 10 3 9 3

输出样例:

╮(╯▽╰)╭
<(@Д=)/~
o(^ε^)o
Are you kidding me? @\/@

思路

使用vector<vector<string>>做二维数组存储表情,最后根据参数输出。

注意事项

  1. 注意第一行有空格,直接用cin无法读入,需要用到string里面的的getline函数。
  2. 字符串取子串的第一个参数是下标,第二个参数是长度
  3. 要注意给出的顺序不仅仅要和数组大小比较,也要判断是否小于1。
  4. 很神奇的问题:用Java编写了个一模一样的逻辑,但答案全部错误。C++写的代码通过了。

代码

#include <iostream>
#include <vector>
#include <string>
using namespace std;

int main() {

    vector<vector<string>> v;
    for (size_t i = 0; i < 3; i++) {
        vector<string> row;
        string line;
        getline(cin, line);

        string tmp;
        bool isStart = false;
        for (size_t j = 0; j < line.length(); j++) {
            if (line[j] == '[') {
                isStart = true;
            } else if (line[j] == ']') {
                isStart = false;
                row.push_back(tmp);
                tmp = "";
            } else {
                if (isStart) {
                    tmp += line[j];
                }
            }
        }

        v.push_back(row);
    }

    int N;
    cin >> N;
    for (size_t i = 0; i < N; i++) {
        int a, b, c, d, e;
        cin >> a >> b >> c >> d >> e;
        if (a<1 || b<1 || c<1 || d<1 || e<1 || a>v[0].size() || b>v[1].size() || c>v[2].size() || d>v[1].size() || e>v[0].size()) {
            cout << "Are you kidding me? @\\/@" << endl;
            continue;
        }
        cout << v[0][a - 1] << "(" << v[1][b - 1] << v[2][c - 1] << v[1][d - 1] << ")" << v[0][e - 1] << endl;
    }
}

1053 住房空置率 (20 分)

题目

在不打扰居民的前提下,统计住房空置率的一种方法是根据每户用电量的连续变化规律进行判断。判断方法如下:

  • 在观察期内,若存在超过一半的日子用电量低于某给定的阈值 e,则该住房为“可能空置”;
  • 若观察期超过某给定阈值 D 天,且满足上一个条件,则该住房为“空置”。

现给定某居民区的住户用电量数据,请你统计“可能空置”的比率和“空置”比率,即以上两种状态的住房占居民区住房总套数的百分比。

输入格式:

输入第一行给出正整数 N(≤1000),为居民区住房总套数;正实数 e,即低电量阈值;正整数 D,即观察期阈值。随后 N 行,每行按以下格式给出一套住房的用电量数据:

K E1 E2 ... EK

其中 K 为观察的天数,Ei 为第 i 天的用电量。

输出格式:

在一行中输出“可能空置”的比率和“空置”比率的百分比值,其间以一个空格分隔,保留小数点后 1 位。

输入样例:

5 0.5 10
6 0.3 0.4 0.5 0.2 0.8 0.6
10 0.0 0.1 0.2 0.3 0.0 0.8 0.6 0.7 0.0 0.5
5 0.4 0.3 0.5 0.1 0.7
11 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
11 2 2 2 1 1 0.1 1 0.1 0.1 0.1 0.1

输出样例:

40.0% 20.0%

(样例解释:第2、3户为“可能空置”,第4户为“空置”,其他户不是空置。)

代码

#include <iostream>

using namespace std;

int main() {
    int N;
    double e;
    int D;

    int mayEmpty = 0, sureEmpty = 0;
    cin >> N >> e >> D;
    for (size_t i = 0; i < N; i++) {
        int num;
        cin >> num;

        int lowCount = 0;
        for (int j = 0; j < num; j++) {
            double tmp;
            cin >> tmp;
            if (tmp < e) {
                lowCount++;
            }
        }

        if (num <= D) {
            mayEmpty += (lowCount * 2 > num) ? 1 : 0;
        } else {
            sureEmpty += (lowCount * 2 > num) ? 1 : 0;
        }
    }

    printf("%.1f%% %.1f%%", mayEmpty*1.0 / N * 100, sureEmpty*1.0 / N * 100);
}

1054 求平均值 (20 分)

题目

本题的基本要求非常简单:给定 N 个实数,计算它们的平均值。但复杂的是有些输入数据可能是非法的。一个“合法”的输入是 [−1000,1000] 区间内的实数,并且最多精确到小数点后 2 位。当你计算平均值的时候,不能把那些非法的数据算在内。
输入格式:

输入第一行给出正整数 N(≤100)。随后一行给出 N 个实数,数字间以一个空格分隔。

输出格式:

对每个非法输入,在一行中输出 ERROR: X is not a legal number,其中 X 是输入。最后在一行中输出结果:The average of K numbers is Y,其中 K 是合法输入的个数,Y 是它们的平均值,精确到小数点后 2 位。如果平均值无法计算,则用 Undefined 替换 Y。如果 K 为 1,则输出 The average of 1 number is Y。

输入样例 1:

7
5 -3.2 aaa 9999 2.3.4 7.123 2.35

输出样例 1:

ERROR: aaa is not a legal number
ERROR: 9999 is not a legal number
ERROR: 2.3.4 is not a legal number
ERROR: 7.123 is not a legal number
The average of 3 numbers is 1.38

输入样例 2:

2

aaa -9999

输出样例 2:

ERROR: aaa is not a legal number
ERROR: -9999 is not a legal number
The average of 0 numbers is Undefined

注意事项

要考虑输入形如5.的情况,即最后一个测试点,此情况应需能通过。

代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.DecimalFormat;

public class Main {

    public static void main(String[] args) throws NumberFormatException, IOException {
        // TODO Auto-generated method stub
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        reader.readLine();
        String[] params = reader.readLine().split(" ");

        int sum = 0;
        double total = 0;

        String out = "";
        for (int i = 0; i < params.length; i++) {
            double num = 0.0;
            try {
                num = Double.parseDouble(params[i]);
                if (Math.abs(num) - 1000 > 0.00001) {
                    out += "ERROR: " + params[i] + " is not a legal number\n";
                    continue;
                }
                if (params[i].contains(".")) {
                    int dotIndex = params[i].indexOf(".");
                    if (params[i].length() - dotIndex > 3) {
                        out += "ERROR: " + params[i] + " is not a legal number\n";
                        continue;
                    }
                }
                total += num;
                sum++;
            } catch (NumberFormatException e) {
                // TODO: handle exception
                out += "ERROR: " + params[i] + " is not a legal number\n";
                continue;
            }
        }
        if (sum == 0) {
            out += "The average of 0 numbers is Undefined";
        } else if (sum == 1) {
            out += "The average of 1 number is " + new DecimalFormat("0.00").format(total);
        } else {
            out += "The average of " + sum + " numbers is " + new DecimalFormat("0.00").format(total / sum);
        }

        System.out.print(out);
    }
}

1055 集体照 (25 分)

题目

拍集体照时队形很重要,这里对给定的 N 个人 K 排的队形设计排队规则如下:

  • 每排人数为 N/K(向下取整),多出来的人全部站在最后一排;
  • 后排所有人的个子都不比前排任何人矮;
  • 每排中最高者站中间(中间位置为 m/2+1,其中 m 为该排人数,除法向下取整);
  • 每排其他人以中间人为轴,按身高非增序,先右后左交替入队站在中间人的两侧(例如5人身高为190、188、186、175、170,则队形为175、188、190、186、170。这里假设你面对拍照者,所以你的左边是中间人的右边);
  • 若多人身高相同,则按名字的字典序升序排列。这里保证无重名。

现给定一组拍照人,请编写程序输出他们的队形。

输入格式:

每个输入包含 1 个测试用例。每个测试用例第 1 行给出两个正整数 N(≤104,总人数)和 K(≤10,总排数)。随后 N 行,每行给出一个人的名字(不包含空格、长度不超过 8 个英文字母)和身高([30, 300] 区间内的整数)。

输出格式:

输出拍照的队形。即K排人名,其间以空格分隔,行末不得有多余空格。注意:假设你面对拍照者,后排的人输出在上方,前排输出在下方。

输入样例:

10 3
Tom 188
Mike 170
Eva 168
Tim 160
Joe 190
Ann 168
Bob 175
Nick 186
Amy 160
John 159

输出样例:

Bob Tom Joe Nick
Ann Mike Eva
Tim Amy John

思路

  1. 读入信息后,按身高从高到低,名字从z到a排序。
  2. 计算得到每一行的范围,生成该行的排列顺序。
  3. 生成排序顺序的思路:先计算中点位置,然后根据排列的人数向左或右填充。

代码

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <stack>

using namespace std;

struct Info {
    string name;
    int high;
};

int cmp(Info &a, Info &b) {
    return a.high != b.high ? a.high < b.high : a.name > b.name;
}

string printList(int begin, int end, vector<Info> &v);
int main() {
    int N, K;
    cin >> N >> K;

    vector<Info> v;
    for (int i = 0; i < N; i++) {
        string name;
        int high;
        cin >> name >> high;
        Info info = { name,high };
        v.push_back(info);
    }

    sort(v.begin(), v.end(), cmp);

    int step = N / K;
    stack<string> s;
    for (int i = 0, cnt = 0; cnt < K; i += step) {
        //计算某排的起点与终点
        int begin = i;
        int end = cnt == K - 1 ? N : i + step;
        s.push(printList(begin, end, v));
        cnt++;
    }

    while (s.size()!=0) {
        string str = s.top();
        cout << str << endl;
        s.pop();
    }
}

//生成某一行的队伍排列
string printList(int begin, int end, vector<Info> &v) {
    string result = "";
    vector<string> tmp(end - begin);

    //计算第一位站的位置,即中间位置
    int flag = (end - begin) / 2;
    tmp[flag] = v[end - 1].name;

    bool isRight = true;
    int count = 1;
    for (int i = end - 2; i >= begin; i--) {
        string name = v[i].name;
        flag += isRight ? -1 * count : count;
        isRight = !isRight;
        tmp[flag] = name;
        count++;
    }

    for (int i = 0; i < tmp.size(); i++) {
        if (i != tmp.size() - 1) {
            result += tmp[i] + " ";
        } else {
            result += tmp[i];
        }
    }
    return result;
}

1056 组合数的和 (15 分)

题目

给定 N 个非 0 的个位数字,用其中任意 2 个数字都可以组合成 1 个 2 位的数字。要求所有可能组合出来的 2 位数字的和。例如给定 2、5、8,则可以组合出:25、28、52、58、82、85,它们的和为330。

输入格式:

输入在第一行中给出 N(1 < N < 10),随后一行给出 N 个不同的非 0 个位数字。数字间以空格分隔。

输出格式:

输出所有可能组合出来的2位数字的和。

输入样例:

3
2 8 5

输出样例:

330

代码

import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;

public class Main {

    public static void main(String[] args) throws NumberFormatException, IOException {
        // TODO Auto-generated method stub

        Scanner scanner = new Scanner(System.in);
        int num = scanner.nextInt();

        int[] datas = new int[num];

        for (int i = 0; i < num; i++) {
            datas[i] = scanner.nextInt();
        }

        Set<Integer> set = new HashSet<Integer>();
        for (int i = 0; i < num; i++) {
            for (int j = i + 1; j < num; j++) {
                int[] data = getData(datas[i], datas[j]);
                set.add(data[0]);
                set.add(data[1]);
            }
        }

        int sum = 0;
        Iterator<Integer> iterator = set.iterator();
        while (iterator.hasNext()) {
            sum += iterator.next();
        }
        System.out.print(sum);
    }

    private static int[] getData(int i, int j) {
        // TODO Auto-generated method stub
        return new int[] { i * 10 + j, j * 10 + i };
    }
}

1057 数零壹 (20 分)

题目

给定一串长度不超过 105 的字符串,本题要求你将其中所有英文字母的序号(字母 a-z 对应序号 1-26,不分大小写)相加,得到整数 N,然后再分析一下 N 的二进制表示中有多少 0、多少 1。例如给定字符串 PAT (Basic),其字母序号之和为:16+1+20+2+1+19+9+3=71,而 71 的二进制是 1000111,即有 3 个 0、4 个 1。

输入格式:

输入在一行中给出长度不超过 105、以回车结束的字符串。

输出格式:

在一行中先后输出 0 的个数和 1 的个数,其间以空格分隔。

输入样例:

PAT (Basic)

输出样例:

3 4

代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));

        int sum = 0;
        int[] digit = new int[2];

        String input = bf.readLine();
        
        for (int i = 0; i < input.length(); i++) {
            char ch = input.charAt(i);
            if (ch >= 'a' && ch <= 'z') {
                sum += ch - (int)'a' + 1;
            }
            if (ch >= 'A' && ch <= 'Z') {
                sum += ch - (int)'A' + 1;
            }
        }

        while (sum != 0) {
            if (sum % 2 == 0) {
                digit[0]++;
            } else {
                digit[1]++;
            }
            sum /= 2;
        }

        System.out.println(digit[0] + " " + digit[1]);
    }
}

1058 选择题 (20 分)

题目

批改多选题是比较麻烦的事情,本题就请你写个程序帮助老师批改多选题,并且指出哪道题错的人最多。

输入格式:

输入在第一行给出两个正整数 N(≤ 1000)和 M(≤ 100),分别是学生人数和多选题的个数。随后 M 行,每行顺次给出一道题的满分值(不超过 5 的正整数)、选项个数(不少于 2 且不超过 5 的正整数)、正确选项个数(不超过选项个数的正整数)、所有正确选项。注意每题的选项从小写英文字母 a 开始顺次排列。各项间以 1 个空格分隔。最后 N 行,每行给出一个学生的答题情况,其每题答案格式为 (选中的选项个数 选项1 ……),按题目顺序给出。注意:题目保证学生的答题情况是合法的,即不存在选中的选项数超过实际选项数的情况。

输出格式:

按照输入的顺序给出每个学生的得分,每个分数占一行。注意判题时只有选择全部正确才能得到该题的分数。最后一行输出错得最多的题目的错误次数和编号(题目按照输入的顺序从 1 开始编号)。如果有并列,则按编号递增顺序输出。数字间用空格分隔,行首尾不得有多余空格。如果所有题目都没有人错,则在最后一行输出 Too simple

输入样例:

3 4
3 4 2 a c
2 5 1 b
5 3 2 b c
1 5 4 a b d e
(2 a c) (2 b d) (2 a c) (3 a b e)
(2 a c) (1 b) (2 a b) (4 a b d e)
(2 b d) (1 e) (2 b c) (4 a b c d)

输出样例:

3
6
5
2 2 3 4

代码

#include <iostream>
#include <vector>
#include <string>

using namespace std;

struct TiInfo {
    int grade;                          //该题的分值
    int itemNum;                        //选项个数
    int rightItemNum;                   //正确选项个数
    int rightItemList[26] = { 0 };       //正确选项列表
    int wrongCount = 0;                 //本题错的次数
};

int main() {
    int N, M;
    cin >> N >> M;

    //读入题目数据
    vector<TiInfo> tiList;
    for (int i = 0; i < M; i++) {
        TiInfo tmp = TiInfo{};
        cin >> tmp.grade >> tmp.itemNum >> tmp.rightItemNum;
        for (int j = 0; j < tmp.rightItemNum; j++) {
            char ch;
            cin >> ch;
            tmp.rightItemList[ch - 'a'] ++;
        }
        tiList.push_back(tmp);
    }

    //读入学生答题数据
    getchar();
    vector<vector<vector<int>>> stuGrade;
    for (int i = 0; i < N; i++) {
        string tmp;
        getline(cin, tmp);
        vector<vector<int>> tmpList;
        int begin = -1, end = -1;
        for (int j = 0; j < tmp.length(); j++) {
            if (tmp[j] == '(') {
                begin = j;
            } else if (tmp[j] == ')') {
                end = j;
                //利用一维数组存储答案,选中的对应字母的元素值为1
                vector<int> tmpList2(26, 0);
                for (int k = begin; k < end; k++) {
                    if (tmp[k] >= 'a' && tmp[k] <= 'z') {
                        tmpList2[tmp[k] - 'a'] ++;
                    }
                }
                tmpList.push_back(tmpList2);
            }
        }
        stuGrade.push_back(tmpList);
    }

    //是否所有学生的答案都正确
    bool isAllStuRight = true;
    for (int i = 0; i < stuGrade.size(); i++) {
        float grade = 0;
        for (int j = 0; j < stuGrade[i].size(); j++) {
            //第i个学生,第j道题的答案
            vector<int> stuAnsList = stuGrade[i][j];
            //学生是否全对
            bool isAllRight = true;
            for (int k = 0; k < 26; k++) {
                if (stuAnsList[k] != tiList[j].rightItemList[k]) {
                    isAllStuRight = false;
                    isAllRight = false;
                    break;
                }
            }
            int tiGrade = tiList[j].grade;
            grade += isAllRight ? tiGrade : 0;
            if (!isAllRight) {
                tiList[j].wrongCount++;
            }
        }
        printf("%d\n", int(grade));
    }

    if (isAllStuRight) {
        cout << "Too simple" << endl;
        return 0;
    }

    int maxWrongCount = 0;
    for (int i = 0; i < tiList.size(); i++) {
        if (tiList[i].wrongCount > maxWrongCount) {
            maxWrongCount = tiList[i].wrongCount;
        }
    }

    printf("%d ", maxWrongCount);
    vector<int> outList;
    for (int i = 0; i < tiList.size(); i++) {
        if (tiList[i].wrongCount == maxWrongCount) {
            outList.push_back(i + 1);
        }
    }

    for (int i = 0; i < outList.size(); i++) {
        if (i == outList.size() - 1) {
            printf("%d", outList[i]);
        } else {
            printf("%d ", outList[i]);
        }
    }
}

1059 C语言竞赛 (20 分)

题目

C 语言竞赛是浙江大学计算机学院主持的一个欢乐的竞赛。既然竞赛主旨是为了好玩,颁奖规则也就制定得很滑稽:

  • 0、冠军将赢得一份“神秘大奖”(比如很巨大的一本学生研究论文集……)。
  • 1、排名为素数的学生将赢得最好的奖品 —— 小黄人玩偶!
  • 2、其他人将得到巧克力。

给定比赛的最终排名以及一系列参赛者的 ID,你要给出这些参赛者应该获得的奖品。

输入格式:

输入第一行给出一个正整数 N(≤104),是参赛者人数。随后 N 行给出最终排名,每行按排名顺序给出一位参赛者的 ID(4 位数字组成)。接下来给出一个正整数 K 以及 K 个需要查询的 ID。

输出格式:

对每个要查询的 ID,在一行中输出 ID: 奖品,其中奖品或者是 Mystery Award(神秘大奖)、或者是 Minion(小黄人)、或者是 Chocolate(巧克力)。如果所查 ID 根本不在排名里,打印 Are you kidding?(耍我呢?)。如果该 ID 已经查过了(即奖品已经领过了),打印 ID: Checked(不能多吃多占)。

输入样例:

6
1111
6666
8888
1234
5555
0001
6
8888
0001
1111
2222
8888
2222

输出样例:

8888: Minion
0001: Chocolate
1111: Mystery Award
2222: Are you kidding?
8888: Checked
2222: Are you kidding?

代码

#include <iostream>
#include <math.h>

using namespace std;

bool isPrime(int num) {
    if (num == 0 || num == 1) return false;
    if (num == 2) return true;
    for (int i = 2; i <= sqrt(num); i++) {
        if (num%i == 0) {
            return false;
        }
    }
    return true;
}

int main() {
    int N;
    int data[10000] = { -1 };
    bool checked[10000] = { false };

    cin >> N;
    for (size_t i = 0; i < N; i++) {
        cin >> data[i];
    }

    int M;
    cin >> M;
    for (size_t i = 0; i < M; i++) {
        int tmp;
        cin >> tmp;

        int j;
        for (j = 0; j < N; j++) {
            if (data[j] == tmp) {
                if (checked[j]) {
                    printf("%04d: %s\n", data[j], "Checked");
                    break;
                }
                checked[j] = true;
                if (j == 0) {
                    printf("%04d: %s\n", data[j], "Mystery Award");
                } else if (isPrime(j + 1)) {
                    printf("%04d: %s\n", data[j], "Minion");
                } else {
                    printf("%04d: %s\n", data[j], "Chocolate");
                }
                break;
            }
        }
        if (j == N) {
            printf("%04d: %s\n", tmp, "Are you kidding?");
        }
    }
}

1060 爱丁顿数 (25 分)

题目

英国天文学家爱丁顿很喜欢骑车。据说他为了炫耀自己的骑车功力,还定义了一个“爱丁顿数” E ,即满足有 E 天骑车超过 E 英里的最大整数 E。据说爱丁顿自己的 E 等于87。

现给定某人 N 天的骑车距离,请你算出对应的爱丁顿数 E(≤N)。

输入格式:

输入第一行给出一个正整数 N (≤105),即连续骑车的天数;第二行给出 N 个非负整数,代表每天的骑车距离。

输出格式:

在一行中给出 N 天的爱丁顿数。

输入样例:

10
6 7 6 9 3 10 8 2 7 8

输出样例:

6

思路

将序列从小到大排序,从后往前遍历。result初值为1,若a[i]>result,表示a[i]大于1公里(有一天的路程大于1公里),将result++(假设result还没求出),再继续判断。若出现a[i]<=result,则result-1即为所求。

注意事项

  1. E不一定是序列中的数。
  2. 数列1 1 1 1 1的爱丁顿数是0。

代码

#include <iostream>
#include <algorithm>

using namespace std;

int d[100000];

int main() {
    int N;
    cin >> N;

    for (int i = 0; i < N; i++) {
        cin >> d[i];
    }

    sort(d, d + N);

    int result = 1;
    for (int i = N - 1; i >= 0; i--) {
        if (d[i] > result) {
            result++;
            continue;
        }
        break;
    }
    cout << result - 1 << endl;
}

猜你喜欢

转载自blog.csdn.net/weixin_33862041/article/details/87205969
今日推荐