Atcoder Beginner Contest 344 A-E 题解

A - Spoiler

题目:
给一个包含了两个 | 和小写字母的字符串,输出两个 | 之间的子字符串(不包括|

思路
使用 indexOflastIndexOf 找出前后 | 的下标,利用 substring 输出子串即可

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;

class Main {

    private static InputStream is = System.in;

    private static final BufferedReader in = new BufferedReader(new InputStreamReader(is));
    private static final PrintWriter out = new PrintWriter(System.out);

    static void solve() throws IOException {
        String s = in.readLine();
        int a = s.indexOf('|'), b = s.lastIndexOf('|');
        out.println(s.substring(0, a) + s.substring(b + 1));
    }

    public static void main(String[] args) throws IOException {
        int t = 1;
        t = Integer.parseInt(in.readLine());
        while (t -- > 0) {
            solve();
        }
        in.close();
        out.flush();
        out.close();
    }
}

B - Delimiter

题目:
给N个整数,一行一个整数,但是不给出N值,确保第N个数一定为0,倒序输出序列

思路:
判断读入的数是否为0,为0就停止读入即可

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

class Main {

    private static InputStream is = System.in;
    private static final BufferedReader in = new BufferedReader(new InputStreamReader(is));
    private static final PrintWriter out = new PrintWriter(System.out);

    static void solve() throws IOException {
        int t = -1;
        List<Integer> list = new ArrayList<>();
        while (t != 0) {
            t = Integer.parseInt(in.readLine());
            list.add(t);
        }
        for (int i = list.size() - 1; i >= 0; i --) {
            out.println(list.get(i));
        }
    }

    public static void main(String[] args) throws IOException {
        int t = 1;
//        t = Integer.parseInt(in.readLine());
        while (t -- > 0) {
            solve();
        }
        in.close();
        out.flush();
        out.close();
    }
}

C - A+B+C

题目:
给出三个序列A、B、C,以及一个查询序列X,对于每个查询,判断是否能够从A、B、C各找出一个数,其总和等于查询值

思路:
题目数据ABC三个序列的长度最大只有100,因此可以先预处理出来从ABC各找一个数的总和,使用哈希表存储,查询时从哈希表中查询

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.Set;

class Main {

    private static InputStream is = System.in;
    private static final BufferedReader in = new BufferedReader(new InputStreamReader(is));
    private static final PrintWriter out = new PrintWriter(System.out);

    static void solve() throws IOException {
        int n = Integer.parseInt(in.readLine());
        String[] ins = in.readLine().split(" ");
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = Integer.parseInt(ins[i]);
        }
        int m = Integer.parseInt(in.readLine());
        ins = in.readLine().split(" ");
        int[] b = new int[m];
        for (int i = 0; i < m; i++) {
            b[i] = Integer.parseInt(ins[i]);
        }
        int l = Integer.parseInt(in.readLine());
        int[] c = new int[l];
        ins = in.readLine().split(" ");
        for (int i = 0; i < l; i++) {
            c[i] = Integer.parseInt(ins[i]);
        }

        Set<Long> st = new HashSet<>();
        for (int i : a) {
            for (int j : b) {
                for (int k : c) {
                    st.add((long) (i + j + k));
                }
            }
        }
        int q = Integer.parseInt(in.readLine());
        ins = in.readLine().split(" ");
        for (int i = 0; i < q; i++) {
            Long t = Long.parseLong(ins[i]);
            if (st.contains(t)) {
                out.println("Yes");
            } else {
                out.println("No");
            }
        }
    }

    public static void main(String[] args) throws IOException {
        int t = 1;
//        t = Integer.parseInt(in.readLine());
        while (t -- > 0) {
            solve();
        }
        in.close();
        out.flush();
        out.close();
    }
}

D - String Bags

题意:
给出一个字符串 t,以及N个背包,每个背包都有若干个字符串;
初始空串s,执行N次操作,第i次操作在第i个背包中最多选择一个字符串并拼接到s后面,求使 s 等于 t 的最小操作数,如果不能则输出 -1

思路:
一开始使用爆搜,但是TLE

// TLE 代码
static int ans = Integer.MAX_VALUE;
static void solve() throws IOException {
    String t = in.readLine();
    int n = Integer.parseInt(in.readLine());
    List<String[]> bags = new ArrayList<>();
    for (int i = 0; i < n; i ++) {
        String[] ins = in.readLine().split(" ");
        bags.add(ins);
    }
    dfs(bags, 0, 0, "", t);
    out.print(ans == Integer.MAX_VALUE ? -1 : ans);
}

static void dfs(List<String[]> bags, int idx, int cnt, String cur, String target) {
    if (idx == bags.size() || cur.length() >= target.length()) {
        if (cur.equals(target)) {
            ans = Math.min(ans, cnt);
        }
        return;
    }
    if (target.indexOf(cur) != 0) return;
    String[] bag = bags.get(idx);
    for (int i = 1; i < bag.length; i ++) {
        dfs(bags, idx + 1, cnt + 1, cur + bag[i], target);
    }
    dfs(bags, idx + 1, cnt, cur, target);
}

背包的选择是按顺序的,那么第 i 个背包的选择是基于前面 1~i -1 背包的选择,这种是一个动态规划
如果第 i 个背包中选择的字符串s能够与t[j : j + len(s)] 部分匹配,那么该子问题转移为第 i - 1个背包中能够与 t[ : j] 匹配的最小操作数

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

class Main {

    private static InputStream is = System.in;
    private static final BufferedReader in = new BufferedReader(new InputStreamReader(is));
    private static final PrintWriter out = new PrintWriter(System.out);

    static void solve() throws IOException {
        String t = in.readLine();
        int n = Integer.parseInt(in.readLine());
        List<String[]> bags = new ArrayList<>();
        for (int i = 0; i < n; i ++) {
            String[] ins = in.readLine().split(" ");
            bags.add(ins);
        }
        int len = t.length();
        int[][] dp = new int[n + 1][len + 1]; // 选择第 i 个背包时,与t的前j个字符相同的最小操作数
        for (int i = 0; i <= n; i ++) {
            Arrays.fill(dp[i], Integer.MAX_VALUE >> 1);
        }
        dp[0][0] = 0;

        for (int i = 0; i < n; i ++) {
            String[] bag = bags.get(i);
            for (int j = 0; j <= len; j ++) {
            		// 如果不选择当前背包的任何字符串
                dp[i + 1][j] = Math.min(dp[i][j], dp[i + 1][j]);
                for (int k = 1; k < bag.length; k ++) {
                    int strLen = bag[k].length();
                    // 判断当前字符串能否放在[j, j + strLen)处
                    if (j + strLen <= len && t.substring(j, j + strLen).equals(bag[k])) {
                        dp[i + 1][j + strLen] = Math.min(dp[i + 1][j + strLen], dp[i][j] + 1);
                    }
                }
            }
        }
        out.println(dp[n][len] == Integer.MAX_VALUE >> 1 ? -1 : dp[n][len]);
    }

    public static void main(String[] args) throws IOException {
        int t = 1;
//        t = Integer.parseInt(in.readLine());
        while (t -- > 0) {
            solve();
        }
        in.close();
        out.flush();
        out.close();
    }
}

E - Insert or Erase

题意:
给一个序列A,每个元素都不相同,执行Q次操作,每次操作都执行下面操作之一:

  • 1 x y 立即插入y到x后面
  • 2 x 立即移除x
    输出执行Q次操作后的序列

思路:
双向链表实现:

  • 1 x y 仅需要修改 x 和 x 的后面元素
  • 2 x 仅需要 x 的前面元素和后面元素

使用哈希表存储每个元素对应的前面元素和后面元素,记得需要添加哨兵元素,方便查找表头和判断表尾

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

class Main {

    private static InputStream is = System.in;
    private static final BufferedReader in = new BufferedReader(new InputStreamReader(is));
    private static final PrintWriter out = new PrintWriter(System.out);

    static void solve() throws IOException {
        int n = Integer.parseInt(in.readLine());
        int[] a = new int[n];
        Map<Integer, Integer> pre = new HashMap<>(), next = new HashMap<>();
        String[] ins = in.readLine().split(" ");
        for (int i = 0; i < n; i ++) {
            a[i] = Integer.parseInt(ins[i]);
        }
        // 初始化双向链表
        for (int i = 0; i < n; i ++) {
            pre.put(a[i], i == 0 ? -1 : a[i - 1]);
            next.put(a[i], i == n - 1 ? -1 : a[i + 1]);
        }
        // 设置表头哨兵,表尾哨兵在上面
        next.put(0, a[0]);
        pre.put(a[0], 0);

        int q = Integer.parseInt(in.readLine());
        while (q -- > 0) {
            ins = in.readLine().split(" ");
            int op = Integer.parseInt(ins[0]);
            if (op == 1) {
                int x = Integer.parseInt(ins[1]), y = Integer.parseInt(ins[2]);
                int nxt = next.get(x);
                pre.put(y, x); // 新插入的y前面为x
                next.put(y, nxt); // 新插入的y后面为nxt
                pre.put(nxt, y);
                next.put(x, y);
            } else {
                int x = Integer.parseInt(ins[1]);
                int prev = pre.get(x), nxt = next.get(x);
                pre.put(nxt, prev); // 将 x 的前面元素和后面元素相互联系即可
                next.put(prev, nxt);
            }
        }

        int t = next.get(0); // 表头哨兵节点
        while (t != -1) { // 判断表尾
            out.print(t + " ");
            t = next.get(t);
        }
    }
    
    public static void main(String[] args) throws IOException {
        int t = 1;
//        t = Integer.parseInt(in.readLine());
        while (t -- > 0) {
            solve();
        }
        in.close();
        out.flush();
        out.close();
    }
}
  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值