• Code Jam Kickstart 2018 Round H 题解


    这轮真的算比较简单的一轮,做出了两道小数据集,大数据集由于罚时没来得及提交了;

    Problem A. Big Buttons

     
    题意:就是每次按"R"或者“B" 会产生一堆字符串,还有一堆invalid前缀,求不包含这些前缀的所有可能字符串;
     
    小数据集:暴力能解答
    大数据集:开始想到是用2^n直接减,但是没有想到重复的情况是怎样,赛后看分析才知道:
             
    /**
    * 因为invalid string 里面,如果有相同前缀,则短的前缀已经包含了长的前缀的情况:
    * 假设invalid string : {BR, BRBR}
    * 其中以BR开头的已经包含了以BRBR开头的!那么减掉的时候就会多减
    * 所以开始应该将invalid string中重复的前缀找出来,最后只减去不重复的情况!
    */
    package CodeJam;
    
    import java.io.*;
    import java.util.*;
    
    public class RoundH_A {
    
        public static void main(String[] args) {
            File input = new File("/Users/shaw/Downloads/A-large-practice.in");
            File output = new File("/Users/shaw/Downloads/A-large-practice.out");
            Scanner in = null;
            try {
                in = new Scanner(input);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            FileWriter printer = null;
            try {
                printer = new FileWriter(output);
            } catch (IOException e) {
                e.printStackTrace();
            }
            PrintWriter out = new PrintWriter(printer);
            int T = in.nextInt();
    
            for (int num = 1; num <= T; num++) {
                int N = in.nextInt();
                int P = in.nextInt();
                List<String> forbidden = new ArrayList<>();
                for (int i = 0; i < P; i++) {
                    forbidden.add(in.next());
                }
                solveLarge(forbidden, N, num, out);
            }
            in.close();
            out.close();
        }
    
        private static void  solve(List<String> forbidden, int N, int num, PrintWriter out) {
            Set<String> all = new HashSet<>();
            Set<String> fors = new HashSet<>();
            Collections.sort(forbidden, (a, b) -> b.length() - a.length());
    
            getAll(all, forbidden, N, 0,  new StringBuilder());
    
            for (String str : all) {
                for (String forb : forbidden) {
                    if (str.startsWith(forb)) {
                        fors.add(str);
                    }
                }
            }
            long res = all.size() - fors.size();
            out.println("Case #" + num + ": " + res);
            System.out.println("Case #" + num + ": " + res);
        }
    
        static String[] strs = {"R", "B"};
    
        private static void getAll(Set<String> all, List<String> forbs, int N, int idx, StringBuilder sb) {
            for (int i = 0; i < forbs.size(); i++) {
                if (sb.toString().startsWith(forbs.get(i))) return;
            }
    
            if (idx == N) {
                all.add(sb.toString());
                return;
            }
            for (int i = 0; i < 2; i++) {
                sb.append(strs[i]);
                getAll(all, forbs, N,idx + 1, sb);
                sb.delete(sb.length() - 1, sb.length());
            }
        }
    
        /**
         * 2的N次方思路没错,但是没有想到有重复的!
         * 因为invalid string 里面,如果有相同前缀,则短的前缀已经包含了长的前缀的情况:
         * 假设invalid string : {BR, BRBR}
         * 其中以BR开头的已经包含了以BRBR开头的!那么减掉的时候就会多减,那么应该将BRBR找出来,标记为不可减,之后只要减去RB的就行了;
         * 所以开始应该将invalid string中重复的前缀找出来,最后只减去不重复的情况!
         */
        private static void  solveLarge(List<String> forbidden, int N, int num, PrintWriter out) {
            int P = forbidden.size();
            int[] invalid = new int[P];
            //找出前缀中的重复情况
            for (int i = 0; i < P; i++) {
                if (invalid[i] == 1) continue;
                for (int j = i +  1; j < P; j++) {
                    if (invalid[j] == 1) continue;
                    int minLen = Math.min(forbidden.get(i).length(), forbidden.get(j).length());
                    boolean flag = true;
                    for (int k = 0; k < minLen; k++) {
                        if (forbidden.get(i).charAt(k) != forbidden.get(j).charAt(k)) {
                            flag = false;
                            break;
                        }
                    }
                    if (flag) {
                        if (minLen == forbidden.get(i).length()) {
                            invalid[j] = 1;
                        } else {
                            invalid[i] = 1;
                        }
                    }
                }
            }
            long res = 1L << N;
            for (int i = 0; i < P; i++) {
                if (invalid[i] == 1) continue;
                res -= 1L << (N - forbidden.get(i).length());
            }
            out.println("Case #" + num + ": " + res);
            System.out.println("Case #" + num + ": " + res);
        }
    }


    Problem B. Mural

     
    Thanh wants to paint a wonderful mural on a wall that is N sections long. Each section of the wall has a beauty score, which indicates how beautiful it will look if it is painted. Unfortunately, the wall is starting to crumble due to a recent flood, so he will need to work fast!

    At the beginning of each day, Thanh will paint one of the sections of the wall. On the first day, he is free to paint any section he likes. On each subsequent day, he must paint a new section that is next to a section he has already painted, since he does not want to split up the mural.

    At the end of each day, one section of the wall will be destroyed. It is always a section of wall that is adjacent to only one other section and is unpainted (Thanh is using a waterproof paint, so painted sections can't be destroyed).

    The total beauty of Thanh's mural will be equal to the sum of the beauty scores of the sections he has painted. Thanh would like to guarantee that, no matter how the wall is destroyed, he can still achieve a total beauty of at least B. What's the maximum value of B for which he can make this guarantee?

    题意:刷墙,每刷一块左(右)边界掉一块,每次只能刷上一次的相邻的,求能使得刷完后“美丽值”最大的刷墙策略。

    小数据集:分析了几个case,使用贪心的解法,找到数组中长度为N/2的和最大的子数组 O(n^2)

    大数据集:必然是O(n)的解法了,因为数组既然已经是定长的了,就可以用滑动窗口,找到数组中长度为N/2的和最大的子数组。。。(比赛时怎么没想到,傻了)

    package CodeJam;
    
    import java.io.*;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Scanner;
    
    public class RoundH_B {
    
        public static void main(String[] args) {
            File input = new File("/Users/shaw/Downloads/B-large-practice.in");
            File output = new File("/Users/shaw/Downloads/B-large-practice.out");
            Scanner in = null;
            try {
                in = new Scanner(input);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            FileWriter printer = null;
            try {
                printer = new FileWriter(output);
            } catch (IOException e) {
                e.printStackTrace();
            }
            PrintWriter out = new PrintWriter(printer);
            int T = in.nextInt();
    
            for (int num = 1; num <= T; num++) {
                int N = in.nextInt();
                int[] walls = new int[N];
                String str = in.next();
                for (int i = 0; i < N; i++) {
                    walls[i] = str.charAt(i) - '0';
                }
                solveBig(walls, num, N, out);
            }
            in.close();
            out.close();
        }
    
        private static void solve(int[] nums, int num , int N, PrintWriter out) {
            int res = 0, len;
            if (N % 2 == 0) len = N / 2;
            else len = N / 2 + 1;
            for (int i = 0; i < N; i++) {
                int tmpSum = 0;
                for (int j = i; j < N && j < i + len; j++) {
                    tmpSum += nums[j];
                }
                res = Math.max(res, tmpSum);
            }
            out.println("Case #" + num + ": " + res);
            System.out.println("Case #" + num + ": " + res);
        }
    
        /**
         * 滑动窗口,前缀和
         */
        private static void solveBig(int[] nums, int num , int N, PrintWriter out) {
            int res = 0, len = (N + 1) / 2, sum = 0;
    
            int[] sums = new int[N + 1];  //sum[i] 表示前i个的和
            for (int i = 1; i <= N; i++) {
                sum += nums[i - 1];
                sums[i] = sum;
            }
    
            for (int i = len; i <= N; i++) {
                res = Math.max(res, sums[i] - sums[i - len]);
            }
    
            out.println("Case #" + num + ": " + res);
            System.out.println("Case #" + num + ": " + res);
        }
    }
     
     
     
     
     
     
     
     
     
     
     





  • 相关阅读:
    sql优化
    什么是泛型
    Http Status 400
    Hadoop搭建伪分布式 & 上传和下载文件
    Centos64 安装指南
    个人感悟
    zabbix4.0部署
    MySQL引擎
    mysql正则表达式
    k8s自动补全命令
  • 原文地址:https://www.cnblogs.com/shawshawwan/p/9983625.html
Copyright © 2020-2023  润新知