AtCoder Beginner Contest 321 题解 A-D

A - 321-like Checker

原题链接

题目描述
给你一个数n判断它是否为一个好数,一个好数定义为对于这个数字的第i位是否严格小于第i-1位即 d i < d i − 1 d_i \lt d_{i - 1} di<di1。如果这个数是好数输出Yes,否则输出No

思路:模拟+枚举

  • 从第2位开始枚举(下标从1开始),判断是否会出现 d i > d i − 1 d_i \gt d_{i - 1} di>di1,若出现则不是一个好数。
public static void solve() throws IOException{
    String s = readString();
    boolean f = false;
    int n = s.length();
    for (int i = 1; i < s.length(); i++) {
        if ((int)s.charAt(i) >= s.charAt(i - 1)) {
            f = true;// 出现了不严格递增的情况
            break;
        }
    }
    printWriter.println(f ? "No" : "Yes");
}

B - Cutoff

原题链接

题目描述
你进行了N轮考试,即获得了N份成绩单,你现在知道其中的N-1份成绩单的成绩,每一份的成绩为 S i S_i Si( 0 ≤ S i ≤ 100 0 \le S_i \le 100 0Si100),还有一份成绩单丢了,你不知道是哪一份,现在需要你求出那份成绩单的分级,但是成绩要尽可能小,使得在添加上这份成绩单的成绩后,去掉成绩最高分和最低分,剩下的分数要大于等于一个整数X,如果这份成绩单是任意分数都无法满足条件,则输出-1,否则输出那份成绩单的分数。

思路:排序+分类讨论

  • 首先假设丢的这份是最小的数,那么肯定要最小化为0,然后求排序好的已知的中间的前N-2的分数总和是否满足条件,不满足则进行下一步。
  • 假设丢的是中间分数的某一份,那么中间 S 2 ∼ S N − 2 S_2 \sim S_{N-2} S2SN2的分数加上丢失的分数使其大于等于X,但是这个丢失的分数要大于等于 S 1 S_1 S1,小于等于 S N − 1 S_{N-1} SN1,不满足则进行下一步。
  • 最后只可能丢失分数最大的那份,那么直接判断 S 2 ∼ S N − 1 S_2 \sim S_{N-1} S2SN1的分数是否大于等于X,不满足则输出-1
public static void solve() throws IOException{
    int n = readInt(), k = readInt();
    int[] arr = new int[n + 10];
    for (int i = 1; i <= n - 1; i++) {
        arr[i] = readInt();
    }
    Arrays.sort(arr, 1, n);
    int leftSum = 0;
    for (int i = 1; i <= n - 2; i++) {
        leftSum += arr[i];
    }
    if (leftSum >= k) {//少最左边的数,用 0来补
        printWriter.println(0);
    } else {
        //少中间的数
        int midSum = 0;
        for (int i = 2; i <= n - 2; i++) {
            midSum += arr[i];
        }
        if (midSum >= k) {
            printWriter.println(arr[1]);//不补数也能大于等于k,那么用arr[1]来补最好
        } else {
            int left = k - midSum;
            if (left >= arr[1] && left <= arr[n - 1]) {
                printWriter.println(left);//否则用 k - midSum来补
            } else {
            	// 少右边的数
                int rigthSum = 0;
                for (int i = 2; i <= n - 1; i++) {
                    rigthSum += arr[i];
                }
                if (rigthSum >= k) {
                    printWriter.println(arr[n - 1]);
                } else {
                    printWriter.println(-1);
                }
            }
        }
    }
}

C - 321-like Searcher

原题链接

题目描述
一个好数定义为对于这个数字的第i位是否严格小于第i-1位即 d i < d i − 1 d_i \lt d_{i - 1} di<di1。现在要你求出第K小的好数。

思路:dfs

  • 由于一个数能够凑出好数的方案数较少,爆搜即可。注意要开long
static List<Long> list = new ArrayList<>();
static TreeSet<Long> set = new TreeSet<>();// 排序+去重

public static void solve() throws IOException {
    int n = readInt();
    for (int i = 1; i <= 9; i++) {
        dfs(i, i);
    }
    for (long p : set){
        list.add(p);
    }
    printWriter.println(list.get(n - 1));
}

public static void dfs(int u, long cur) {
    if (cur < 0) return;
    if (cur >= 0 && !set.contains(cur)) {
        set.add(cur);
    }
    for (int i = u - 1; i >= 0; i--) {
        dfs(i, 1l * cur * 10 + i);
    }
}

D - Set Menu

原题链接

题目描述
食堂提供N道主菜和M道配菜。第i种主菜的价格是 A i A_i Ai ,第j种配菜的价格是 B j B_j Bj 。套餐包括一道主菜和一道配菜。设主菜和配菜的价格之和为s,则套餐的价格为 m i n ( s , P ) min(s,P) min(s,P)。选择套餐主菜和配菜的方法有 N ∗ M N*M NM种。求所有这些套餐的总价。
输入样例

2 2 7
3 5
6 1

输出样例

24

思路:排序+二分+前缀和

  • 排序不影响答案,先排序,用于二分,二分求的值看代码注释。
  • 对于每一个 a i a_i ai,需要求出有多少个 b i b_i bi加上 a i a_i ai后会大于P,全部用P来替代,剩下的用 a i + b i a_i+b_i ai+bi来替代, b i b_i bi用前缀和维护即可,注意开long
public static void solve() throws IOException {
    int n = readInt(), m = readInt(), k = readInt();
    int[] a = utils.nextIntArray(n), b = utils.nextIntArray(m);
    Arrays.sort(b, 1, m + 1);
    long[] pre = new long[m + 1];
    for (int i = 1; i <= m; i++) {
        pre[i] = 1l * b[i] + pre[i - 1];
    }
    long sum = 0;
    for (int i = 1; i <= n; i++) {
        int left = k - a[i];
        int l = 0, r = m + 1;
        // 找到最后一个小于等于 left的坐标
        while (l + 1 < r) {
            int mid = l + r >> 1;
            if (b[mid] <= left) {
                l = mid;
            } else {
                r = mid;
            }
        }
        sum += 1l * (m - l) * k;// (m-l)个数加上a[i]后会大于k,所以有(m-1)个b[i]被 k替代
        // [1,l]中的数加上a[i]全都小于等于k
        sum += 1l * l * a[i];// 有l个a[i]
        sum += pre[l];// 前[1,l]个b[i]之和
    }
    printWriter.println(sum);
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AtCoder Beginner Contest 134 是一场 AtCoder 的入门级比赛,以下是每道题的简要题解: A - Dodecagon 题目描述:已知一个正十二边形的边长,求它的面积。 解题思路:正十二边形的内角为 $150^\circ$,因此可以将正十二边形拆分为 12 个等腰三角形,通过三角形面积公式计算面积即可。 B - Golden Apple 题目描述:有 $N$ 个苹果和 $D$ 个盘子,每个盘子最多可以装下 $2D+1$ 个苹果,求最少需要多少个盘子才能装下所有的苹果。 解题思路:每个盘子最多可以装下 $2D+1$ 个苹果,因此可以将苹果平均分配到每个盘子中,可以得到最少需要 $\lceil \frac{N}{2D+1} \rceil$ 个盘子。 C - Exception Handling 题目描述:给定一个长度为 $N$ 的整数序列 $a$,求除了第 $i$ 个数以外的最大值。 解题思路:可以使用两个变量 $m_1$ 和 $m_2$ 分别记录最大值和次大值。遍历整个序列,当当前数不是第 $i$ 个数时,更新最大值和次大值。因此,最后的结果应该是 $m_1$ 或 $m_2$ 中较小的一个。 D - Preparing Boxes 题目描述:有 $N$ 个盒子和 $M$ 个物品,第 $i$ 个盒子可以放入 $a_i$ 个物品,每个物品只能放在一个盒子中。现在需要将所有的物品放入盒子中,每次操作可以将一个盒子内的物品全部取出并分配到其他盒子中,求最少需要多少次操作才能完成任务。 解题思路:首先可以计算出所有盒子中物品的总数 $S$,然后判断是否存在一个盒子的物品数量大于 $\lceil \frac{S}{2} \rceil$,如果存在,则无法完成任务。否则,可以用贪心的思想,每次从物品数量最多的盒子中取出一个物品,放入物品数量最少的盒子中。因为每次操作都会使得物品数量最多的盒子的物品数量减少,而物品数量最少的盒子的物品数量不变或增加,因此这种贪心策略可以保证最少需要的操作次数最小。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值