2023/05/08~14 刷题记录

A - Plus and Multiply

题意:2023/05/08~14 刷题记录_第1张图片

题解:
题目说可以将集合里面的数字 *a 或者 +b 操作,并将新的值放进集合中,首先想到 dfs 暴力求解,但是太暴力了,直接 时间超限 。通过观察我们可以知道,要求 n 是否在集合中,如果在 一定会存在 一个 x1、x2 使得 a(乘x1次) + b(加x2次) == n。为什么不会出现先加上 b 再乘上 a 的情况呢?因为如果你先加上了一个 b,那么后面乘上 a 相当于是 加了 a 个 b。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int t = sc.nextInt();

        while (t-- != 0) {
            long n = sc.nextInt();
            long a = sc.nextInt();
            long b = sc.nextInt();

            boolean k = false;

            if (a == 1) {
                if (n % b == 1 || b == 1) System.out.println("Yes");
                else System.out.println("No");
                continue;
            }

            for (int i = 1; i <= n; i *= a) {
                if ((n - i) % b == 0)
                    k = true;
                if (k)
                    break;
            }

            if (k)
                System.out.println("Yes");
            else
                System.out.println("No");
        }
    }
}

B - Air Conditioner

题目大意:
2023/05/08~14 刷题记录_第2张图片

题解:
那么我们可以按顾客到达的顺序来处理。 维护温度可能的区间[L,R]。从顾客i-1到i时,过去的时间d = t - t(i-1),温度可能的区间[L, R]=[L - d,R+d]。
又因为要满足第i个顾客的需求,所以我们将这个区间与[l,r;]取交集即可。取交集:[L,R] ∩ [l, ri]=[max(L, li), min(R, ri)]

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int t = sc.nextInt();

        while (t-- != 0) {
            int n = sc.nextInt();
            int m = sc.nextInt();

            ArrayList<Guest> guests = new ArrayList<>(n);
            for (int i = 0; i < n; i++) 
                guests.add(new Guest(sc.nextInt(), sc.nextInt(), sc.nextInt()));
            
            // 根据时间排序
            guests.sort((o1, o2) -> o1.getT() - o2.getT());

            int l = m, r = m, now = 0;
            boolean k = false;
            for (Guest guest : guests) {
                int hh = guest.getH();
                int ll = guest.getL();
                int time = guest.getT();

                int x = time - now;
                now = time;
                l -= x;
                r += x;
                k = true;

                // 取区间最小值。
                // 一个是可以到达的最低和最高温度,一个是为满足客户可以到达的最低最高温度
                l = Math.max(l, ll);
                r = Math.min(r, hh);

                if (l > r) {
                    k = false;
                    break;
                }
            }

            if (k)
                System.out.println("YES");
            else
                System.out.println("NO");
        }
    }
}

class Guest {
    int t, l, h;

    public int getT() {
        return t;
    }

    public void setT(int t) {
        this.t = t;
    }

    public int getL() {
        return l;
    }

    public void setL(int l) {
        this.l = l;
    }

    public int getH() {
        return h;
    }

    public void setH(int h) {
        this.h = h;
    }

    public Guest(int t, int l, int h) {
        this.t = t;
        this.l = l;
        this.h = h;
    }
}

C - Theatre Square

大致题义:
在这里插入图片描述

题解:
分别求出该广场的长和宽分别需要多长的石板,然后将 长和宽 相乘即可。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();
        int m = sc.nextInt();
        int a = sc.nextInt();
        
        // 求解长和宽,并相乘输出
        System.out.println((long) Math.ceil((double) m / a) * (long) Math.ceil(n / (double) a));
    }
}

D - Bargaining Table

大致题义:
在这里插入图片描述

题解:
使用 二维前缀和 取计算矩阵周长是否全是 ‘0‘,也就是是否存在 ‘1’。如果不存在 ‘1’,则尝试作为答案,判断大小。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        n = sc.nextInt();
        m = sc.nextInt();
        sc.nextLine();

        // 输入地图,并计算 二维前缀和
        int[][] map = new int[n + 1][m + 1];
        sum = new int[n + 1][m + 1];
        for (int i = 1; i <= n; i++) {
            String s = sc.nextLine();

            // 计算 二维前缀和
            int temp = 0;
            for (int j = 1; j <= m; j++) {
                map[i][j] = Integer.parseInt(String.valueOf(s.charAt(j - 1)));
                temp += map[i][j];
                sum[i][j] = sum[i - 1][j] + temp;
            }
        }

        // 全遍历 并剪枝
        int ans = 0;
        for (int x1 = 1; x1 <= n; x1++)
            for (int y1 = 1; y1 <= m; y1++)
                if (map[x1][y1] == 0) 
                    for (int x2 = x1; x2 <= n; x2++)
                        for (int y2 = y1; y2 <= m; y2++)
                            if (fun(x1, y1, x2, y2) == 0)
                                ans = Math.max(ans, ((x2 - x1 + 1) + (y2 - y1 + 1)) * 2);

        System.out.println(ans);
    }

    static int n, m;
    //存储 二维前缀和
    static int[][] sum;

    // 求 (x1, y1) 到 (x2, y2) 之间的二维前缀和
    static int fun(int x1, int y1, int x2, int y2) {
        return sum[x2][y2] - sum[x1 - 1][y2] - sum[x2][y1 - 1] + sum[x1 - 1][y1 - 1];
    }
}

E - Coins

大致题义:
2023/05/08~14 刷题记录_第3张图片

题解:
求解出素数,因为一个合数就是由很多素数组成,从小到大 一个一个 除尽 依次输出即可。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();
        System.out.print(n + " ");

        ArrayList<Integer> primeNumbers = getPrimeNumbers(n);

        // 遍历每一个素数, 因为合数就是由若干个素数组成,让这个数除每个素数
        for (Integer primeNumber : primeNumbers) {
            while (n % primeNumber == 0) {
                n /= primeNumber;
                System.out.print(n + " ");

                if (n == 1)
                    break;
            }
        }
    }

    // 求素数,埃筛
    private static ArrayList<Integer> getPrimeNumbers(int n) {
        ArrayList<Integer> primeNumbers = new ArrayList<>();

        int len = n + 1;

        // 初始化素数
        int[] temp = new int[len];
        temp[0] = 1;
        temp[1] = 1;

        for (int i = 2; i < len; i++) {
            if (temp[i] == 0) {
                for (int j = i * 2; j < len; j += i)
                    temp[j] = 1;

                primeNumbers.add(i);
            }
        }
        return primeNumbers;
    }
}

F - Alice, Bob and Chocolate

大致题义:
在这里插入图片描述

题解:
使用 双指针 循环遍历,L 代表 左指针 指向左下标,R 代表 右指针 指向右下标

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();

        int[] a = new int[n];
        for (int i = 0; i < n; i++)
            a[i] = sc.nextInt();

        // 使用 双指针 指向数组,依次遍历
        int l = 0, r = n - 1;
        while (l + 1 < r) {
            if (a[l] < a[r]) {
                a[r] -= a[l];
                l++;
            } else if (a[l] > a[r]) {
                a[l] -= a[r];
                r--;
            } else {
                l++;
                r--;
            }
        }

        // 因为 下标 比 序号 小 1,所以下标需要加一 变成个数
        l++;
        // 同时,因为他们可能同时到达同一个 “巧克力棒”,而女士优先
        // 故取 l 作为 Alice 答案,n-l 作为 Bob 答案
        System.out.println(l + " " + (n - l));
    }
}

H - Sale

大致题义:
在这里插入图片描述

题解:
题目就是要求我们求出 在 m 个电器的范围内,最大可以 “赚” 多少钱,也就是看 电视机 的负数价格有多少。
很显然,快排,然后遍历。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();
        int m = sc.nextInt();

        ArrayList<Integer> a = new ArrayList<>();
        for (int i = 0; i < n; i++)
            a.add(sc.nextInt());

        // 快排
        Collections.sort(a);

        // 遍历 至多 m 个,求负数之和为多少
        int ans = 0;
        for (int i = 0; i < m; i++)
            if (a.get(i) < 0)
                ans -= a.get(i);
            else
                break;

        System.out.println(ans);
    }
}

I - Laptops

大致题义:
2023/05/08~14 刷题记录_第4张图片

题解:
使用快排对 笔记本的价格 进行排序,然后再依次遍历,判断 每一台计算机 是否 比前一台计算机质量高。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();

        ArrayList<Goods> goods = new ArrayList<Goods>();
        for (int i = 0; i < n; i++)
            goods.add(new Goods(sc.nextInt(), sc.nextInt()));

        // 根据 笔记本 的价格 快速排序
        goods.sort((o1, o2) -> o1.a - o2.a);

        boolean k = false;
        // 如果有一台 笔记本 在价值低的情况下,反而质量更好 就标记
        // ps:在这里为什么不要 把每台计算机前面的所有计算机都比较一下质量呢?
        // 因为 这个质量一定是呈现递增的趋势,不然 循环已经终止了(也就是说,前一台计算机一定是 前面所有计算机中 质量最好的)
        for (int i = 1; i < goods.size(); i++) {
            if (goods.get(i - 1).b > goods.get(i).b) {
                k = true;
                break;
            }
        }

        if (k)
            System.out.println("Happy Alex");
        else
            System.out.println("Poor Alex");
    }
}

class Goods {
    int a, b;

    Goods(int a, int b) {
        this.a = a;
        this.b = b;
    }
}

J - Trust Nobody

题目大意:
2023/05/08~14 刷题记录_第5张图片

题解:
注意题目中所说的 “至少”。
通过分析题目,我们了解到了,假设一组数据中答案是 5,则 说大于 5 的人则在说假话。
因此,我们使用桶排 统计所有人说的 x 的次数,使用 a[x] 表示。
再遍历的过程中 使用前缀和优化循环次数。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int t = sc.nextInt();

        while (t-- != 0) {
            int n = sc.nextInt(), x;

            // 桶排 统计所有人说的 x 的次数,使用 a[x] 表示。
            int[] a = new int[n];
            for (int i = 0; i < n; i++) {
                x = sc.nextInt();
                // 如果 大于等于 n,则肯定在说谎,不必统计
                if (x < n)
                    a[x]++;
            }

            // 前缀和 统计结果,如果没有答案输出 -1
            int ans = -1, sum = 0;
            for (int i = 0; i < n; i++) {
                sum += a[i];

                if (i == n - sum) {
                    ans = i;
                    break;
                }
            }

            System.out.println(ans);
        }
    }
}

K - Dreaming of Freedom

题目大意:
2023/05/08~14 刷题记录_第6张图片
题解:
模拟题。
注意剪枝,时间复杂度。
如果 “程序员” 的个数 n 是一个合数,也就是可以被素数整除的话(同时这个素数得 小于 题目的个数 m)则可以一直选下去,没有尽头。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int t = sc.nextInt(), n, m;

        boolean k;
        while (t-- != 0) {
            n = sc.nextInt();
            m = sc.nextInt();

            if (n == 1 || m == 1) {
                System.out.println("YES");
                continue;
            } else if (m >= n) {
                System.out.println("NO");
                continue;
            }

            // 注意剪枝 i <= n / i
            k = false;
            for (int i = 2; i <= m && i <= n / i; i++) {
                if (n % i == 0) {
                    k = true;
                    break;
                }
            }

            if (!k)
                System.out.println("YES");
            else
                System.out.println("NO");
        }
    }
}

L - Lunatic Never Content

题目大意:
2023/05/08~14 刷题记录_第7张图片

题解:
这道题不难,但解决前需要知道几个知识点:
2023/05/08~14 刷题记录_第8张图片
因此,这道题变成了找所有对数差的最大公因数。

除此之外,x 可以为无限大的情况就是数组 a 本身是回文的情况,需要特判输出 0。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int t = sc.nextInt();

        while (t-- != 0) {
            int n = sc.nextInt();

            ArrayList<Integer> a = new ArrayList<>(n);
            for (int i = 0; i < n; i++)
                a.add(sc.nextInt());
            
            Set<Integer> ans = new HashSet<>(n);
            for (int i = 0; i < n / 2; i++)
                ans.add(Math.abs(a.get(i) - a.get(n - i - 1)));
            
            // 如果 都是 0 说明 这个本身就是一个回文数,可以被无限大除 输出 0
            ans.remove(0);
            if (ans.size() > 0)
                System.out.println(fun(ans));
            else
                System.out.println(0);
        }
    }

    // 求解一个集合中所有数的 最小公约数
    static int fun(Set<Integer> ans) {
        int result = ans.iterator().next();

        for (Integer an : ans) {
            int min = Math.min(result, an);

            while (result % min != 0 || an % min != 0)
                min--;

            result = min;
        }

        return result;
    }
}

M - Running Miles

题目大意:
在这里插入图片描述

题解:
两个指针指向 左右最合适的边界点。
遍历每个点寻找答案,把每个点(去首尾)当作为中间点,加上 左右边界 最合适的点 求解答案

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int t = sc.nextInt();

        while (t-- != 0) {
            int n = sc.nextInt();

            ArrayList<Integer> a = new ArrayList<>(n);
            for (int i = 0; i < n; i++)
                a.add(sc.nextInt());

            // 求解 只考虑 后面 i 个元素时,r 取哪个值最合适,存储哪个值的下标
            int[] last = new int[n];
            last[n - 1] = n - 1;
            for (int i = 1; i < n; i++)
                last[n - 1 - i] = a.get(last[n - i]) - last[n - i] > a.get(n - i) - (n - i) ? last[n - i] : n - i;

            // 两个指针指向 左右最合适的边界点。
            int l = 0, r, ans = 0;
            // 遍历每个点寻找答案,把每个点(去首尾)作为中间点,加上 左右边界 最合适的点 求解答案
            for (int i = 1; i < a.size() - 1; i++) {
                r = last[i];

                ans = Math.max(ans, a.get(l) + a.get(i) + a.get(r) + l - r);

                if (a.get(l) + l - i <= a.get(i))
                    l = i;
            }

            System.out.println(ans);
        }
    }
}

你可能感兴趣的:(Java刷题记录,java,算法)