2023/05/02~07 刷题记录

A - AABCC

 题义:

 题解:

        读完题目可以想到直接暴力,但是肯定超时别想了。

        因为 a b c 都是素数,所以我们可以先求出所有的素数 进行减少循环的次数,然后遍历。在遍历过程中,我们也要去进行剪枝 ,如果说 a 的五次方大于了目标值,那后面肯定就都大于了,以此类推。

import java.util.*;

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

        long n = sc.nextLong();

        // 求素数 并放入集合中
        ArrayList primeNumbers = new ArrayList<>(1000);
        getPrimeNumbers(n, primeNumbers);

        // 使用 HashSet 集合存储答案
        HashSet ans = new HashSet<>();
        long a, b, c, e;
        // 遍历所有可能 并使用if剪枝,如果说 a 的五次方大于了目标值,那后面肯定就都大于了
        for (int i = 0; i < primeNumbers.size(); i++) {
            a = primeNumbers.get(i);
            if (a * a * a * a * a > n)
                break;

            for (int j = i + 1; j < primeNumbers.size(); j++) {
                b = primeNumbers.get(j);
                if (a * a * b * b * b > n)
                    break;

                for (int k = j + 1; k < primeNumbers.size(); k++) {
                    c = primeNumbers.get(k);

                    e = a * a * b * c * c;
                    if (e <= n)
                        ans.add(e);
                    else
                        break;
                }
            }
        }

        // Set 集合中的个数 为答案的数量
        System.out.println(ans.size());
    }

    // 求素数,埃筛
    private static void getPrimeNumbers(long n, ArrayList primeNumbers) {
        int len = (int) Math.sqrt(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);
            }
        }
    }
}

B - Same Map in the RPG World

题义:

2023/05/02~07 刷题记录_第1张图片

 题解:
        我们还是可以第一眼想到暴力求解,但是这个暴力不能太直接了。

        我们可以把每一个点,当作是起点,然后根据这个点 去和 B 矩阵从(0, 0)开始比对。完全相同则为Yes。

import java.util.*;

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

        int h = sc.nextInt();
        int w = sc.nextInt();
        sc.nextLine();

        // 存放数据矩阵
        char[][] a = new char[50][50];
        char[][] b = new char[50][50];
        for (int i = 0; i < h; i++)
            a[i] = sc.nextLine().toCharArray();
        for (int i = 0; i < h; i++)
            b[i] = sc.nextLine().toCharArray();

        // 先设为 false,遍历每一个点,把这些点当作为起点,然后和 B 矩阵对比
        boolean k = false;
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                if (judge(a, b, i, j, h)) {
                    k = true;
                    break;
                }
            }
        }

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

    static boolean judge(char[][] a, char[][] b, int x, int y, int h) {
        int t = y;
        for (int i = 0; i < h; i++) {
            // 遍历 如果 x 大于了高度 h 则说明 A 矩阵已经从起点遍历到了最后 需要把 x+i 放到第一行
            x = x + i >= h ? x - h : x;
            y = t;
            for (int j = 0; j < a[i].length; j++) {
                // y 同理
                y = y + j >= a[i].length ? y - a[i].length : y;

                if (a[x + i][y + j] != b[i][j]) {
                    return false;
                }
            }
        }

        return true;
    }
}

 C - Cross

题义:

2023/05/02~07 刷题记录_第2张图片

题解:

        遍历每一个点,把该点当作 X 图形的中心,求出这个点最大的 X 图形长度。既然是求最大,那么就不用考虑是否会交叉等问题。

import java.util.*;

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

        h = sc.nextInt();
        w = sc.nextInt();
        sc.nextLine();

        for (int i = 0; i < h; i++) 
            mp[i] = sc.nextLine().toCharArray();

        // 遍历每一个点当作中心
        for (int i = 0; i < h; i++)
            for (int j = 0; j < w; j++)
                if (mp[i][j] == '#')
                    fun(i, j);
                
        // 输出答案
        for (int i = 1; i <= Math.min(h, w); i++) 
            System.out.print(ans[i] + " ");
    }

    static int[] ans = new int[110];
    static char[][] mp = new char[110][100];
    static int h, w;

    // 求以(x, y)为中心,最大的 X 图像为多大
    static void fun(int x, int y) {
        int i = 1;
        while (true) {
            // 越界 就退出循环
            if (x - i < 0 || y - i < 0 || x + i >= h || y + i >= w)
                break;
            // 不能抵达 就退出循环
            if (mp[x - i][y - i] != '#' || mp[x + i][y - i] != '#' || mp[x - i][y + i] != '#' || mp[x + i][y + i] != '#')
                break;

            i++;
        }

        // 存进答案数组中
        ans[i - 1]++;
    }
}

D - Find by Query

2023/05/02~07 刷题记录_第3张图片

题解:
        交互题。

        已知 s1 = 0,sn = 1。则不管中间是什么值,肯定会有一个分界的点,我们就是要求出这个点(任求一个)。很容易我们想到二分的方法,注意临界条件和判断条件。

import java.util.*;

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

        int n = sc.nextInt();

        // 二分 每次询问中间的值,如果是 0,则往右边靠,因为最右边是 1。
        // 那肯定有一个分界点。如果是 1,同理。
        int l = 1, r = n, mid, res;
        while (l <= r) {
            mid = (l + r) / 2;
            System.out.println("?" + mid);
            res = sc.nextInt();
            if (res == 0)
                l = mid + 1;
            else
                r = mid - 1;
        }

        System.out.println("!" + r);
    }
}

E - Dango

题义:
2023/05/02~07 刷题记录_第4张图片

题解:

        简单模拟题,注意细节就好了。

import java.util.*;

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

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

        String s = sc.nextLine();
        int ans = -1, l, r = -1;
        for (int i = 0; i < s.length(); i++) {
            // 如果该点为 -,则看是否为最大值 尝试存入答案
            if (s.charAt(i) == '-') {
                l = r;
                r = i;

                ans = Math.max(ans, r - l - 1);
            }
        }

        // 特殊情况,当 r == -1 则说明没有 -
        // 不为 r != -1 则求 从字符串最后到 倒数第一个 - 的距离 也可能为答案
        if (r != -1)
            ans = Math.max(ans, s.length() - r - 1);
        // 如果答案为 0,则没有 o,输出 -1
        if (ans == 0)
            ans--;
        System.out.println(ans);
    }
}

F - Cards Query Problem

题义:

2023/05/02~07 刷题记录_第5张图片

题解:

        分别使用两个集合去存储数据。使用 ArrayList 集合当作一个盒子,把元素存进该集合中。

        使用 TreeSet 集合,存储对应下标卡片,在哪些盒子中存在。(其中 因为实现了 Set 接口 所以可以自动去重,又是 TreeSet 可以自动排序)

import java.util.*;

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

        int n = sc.nextInt();
        int q = sc.nextInt();
        int i, x;

        // 创建两个集合,分别存放一个盒子中有的卡片
        ArrayList> arrayLists = new ArrayList<>(n);
        // 存放一个卡片的值 在哪些盒子中存在于 哪些盒子中,因为需要去重所以选择Set集合,又因为TreeSet自带排序
        ArrayList> treeSets = new ArrayList<>(200010);
        for (i = 0; i < 200010; i++)
            treeSets.add(new TreeSet<>());
        for (i = 0; i < n; i++)
            arrayLists.add(new ArrayList<>(100));

        while (q-- != 0) {
            switch (sc.nextInt()) {
                case 1:
                    x = sc.nextInt();
                    i = sc.nextInt();

                    // 放入对应的集合
                    treeSets.get(x).add(i);
                    arrayLists.get(i - 1).add(x);
                    break;
                case 2:
                    i = sc.nextInt();

                    // 排序后输出 盒子中的全部卡片
                    ArrayList integers = arrayLists.get(i - 1);
                    Collections.sort(integers);
                    for (Integer integer : integers)
                        System.out.print(integer + " ");
                    System.out.println();
                    break;
                case 3:
                    x = sc.nextInt();

                    // 输出对应卡片的集合里的 所有盒子(已经自动排序了)
                    TreeSet treeSet = treeSets.get(x);
                    for (Integer integer : treeSet)
                        System.out.print(integer + " ");
                    System.out.println();
                    break;
            }
        }
    }
}

H - Writing a Numeral

 题义:

2023/05/02~07 刷题记录_第6张图片

题解:

        全程使用一个 long 类型维护。

        操作一:加一个数后,进行对这个值取模。

        操作二:删除最前面的数,删除时考虑 当时的位数(队列的位数),而不是维护的数值的位数。因为维护的数会被取模。而在进行减的时候,也要先进行取模,否则可能会数字过大,这里还可以使用预处理进行减少计算的时间与次数。

        操作三:输出维护的这个数值。

import java.util.*;

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

        long n = sc.nextLong();

        // 需要 mod 的值
        final int INF = 998244353;
        // 初始化数值为 1,待会用来做乘法
        long ans = 1;
        // 预处理
        long[] div = new long[600005];
        div[0] = 1;
        for (int i = 1; i < 600005; i++)
            div[i] = div[i - 1] * 10 % INF;

        // 使用 LinkedList 集合来存储各个位上的数字,方便尾插和弹出队头
        LinkedList linkedList = new LinkedList<>();
        linkedList.add(1);
        for (long i = 0; i < n; i++) {
            switch (sc.nextInt()) {
                case 1:
                    // 插入队尾
                    int a = sc.nextInt();
                    linkedList.addLast(a);
                    ans = ans * 10 + a;
                    ans = myMod(ans, INF);
                    break;
                case 2:
                    // 移除头节点,并将维护的数字减去这个头节点对应的值
                    Integer first = linkedList.removeFirst();
                    ans -= (long) first * div[linkedList.size()];
                    // 减去之后可能为负数,改为自己定义的 mod 方法
                    ans = myMod(ans, INF);
                    break;
                case 3:
                    // 输出维护的数值
                    System.out.println(ans);
                    break;
            }
        }
    }

    // mod 可能为负数,自定义 mod
    static long myMod(long x, long mod) {
        x %= mod;
        while (x < 0)
            x += mod;
        return x;
    }
}

 J - M<=ab

 题义:

2023/05/02~07 刷题记录_第7张图片

 题解:

        阅读完题目很容易想到暴力,也就是从 M 开始,一个一个试看是否有两个数字可以相乘的值为它,并且这两个值都小于 N。但是肯定超时。。。

        改变思路,我们可以从 1 开始 (设为 i),求出一个与 i 相乘 大于等于 M 且最接近 M 的值。推导出 

(m + i - 1) / i;

        为什么要 +i ?因为 M / i * i 的值可能会小于 M,加了 i 之后,计算出来的结果一定会使得 求出来的值 乘以 i 大于等于 M。

import java.util.*;

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

        long n = sc.nextLong();
        long m = sc.nextLong();
        long k, ans = Long.MAX_VALUE;

        for (long i = 1; i <= n; i++) {
            // 求出一个 与 i 相乘 大于等于 M 的值,且该值为最接近 M 的
            k = (m + i - 1) / i;

            // 剪枝,如果 i 大于了 k 的话,其实后面的值 之前都遍历过了,break 跳出
            if (i <= k) {
                // 如果 k 在答案的范围内(1-n),则对比一下结果
                if (k <= n)
                    ans = Math.min(ans, i * k);
            } else {
                break;
            }
        }

        if (ans == Long.MAX_VALUE)
            System.out.println(-1);
        else
            System.out.println(ans);
    }
}

K - Gap Existence

 题义:

 题解:

        使用 HashSet 进行存储数据(包含了去重、快速查找功能)。

import java.util.*;

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

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

        // 使用 HashSet 存储,满足题目的快速查找(hash值)和去重剪枝需求
        HashSet hashSet = new HashSet<>(n);
        for (long i = 0; i < n; i++)
            hashSet.add(sc.nextInt());

        // 判断是否含有这个值,a - x 的值
        boolean k = false;
        for (Integer a : hashSet) {
            if (hashSet.contains(a - x)) {
                k = true;
                break;
            }
        }

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

L - 2xN Grid

题义:

2023/05/02~07 刷题记录_第8张图片

题解:
        简单模拟题。

import java.util.*;

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

        long len = sc.nextLong();
        long n1 = sc.nextLong();
        long n2 = sc.nextLong();

        ArrayList nodes = new ArrayList<>();
        for (int i = 0; i < n1; i++)
            nodes.add(new Node(sc.nextLong(), sc.nextLong()));

        int now = 0;
        long ans = 0, x = 0, l = 0, xx = 0, ll = 0;
        for (int i = 0; i < n2; i++) {
            x = sc.nextLong();
            l = sc.nextLong();

            // 将 B 序列的值 循环消耗完
            while (l != 0) {
                if (ll == 0) {
                    Node node = nodes.get(now++);
                    xx = node.x;
                    ll = node.l;
                }

                if (l <= ll) {
                    if (x == xx)
                        ans += l;
                    ll -= l;
                    l = 0;
                } else {
                    if (x == xx)
                        ans += ll;
                    l -= ll;
                    ll = 0;
                }
            }
        }

        System.out.println(ans);
    }

    static class Node {
        long x, l;

        Node(long x, long l) {
            this.x = x;
            this.l = l;
        }
    }
}

M - Bank

题义:

2023/05/02~07 刷题记录_第9张图片

题解:

        该题目对 Java 选手不太友好,这样都超时。

        因为,题目只有操作二可以删除元素,而在删除之前肯定会添加该元素,所以操作一都不用管。操作三时,如果 bool 值为 true 则说明该值已经被删除了,则 ++ 判断下一个值。

import java.util.Scanner;

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

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

        // 创建一个 bool 数组判断是否删除了该元素
        boolean[] booleans = new boolean[n+1];
        int last = 1;

        for (int i = 0; i < q; i++) {
            switch (sc.nextInt()) {
                case 2:
                    // 操作二 删除一个元素
                    int a = sc.nextInt();
                    booleans[a] = true;
                    break;
                case 3:
                    // 操作三 输出一个最小的没有被删除的元素
                    while (booleans[last])
                        last ++;
                    System.out.println(last);
                    break;
            }
        }
    }
}

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