AtCoder Beginner Contest 318 题解 A-E

目录

  • A - Full Moon
  • B - Overlapping sheets
  • C - Blue Spring
  • D - General Weighted Max Matching
  • E - Sandwiches

A - Full Moon

原题链接

题目描述
今天是第一天,高桥第一次看到满月是第M天,之后每隔P天可再次看到满月,问能看到满月的次数

思路:模拟

public static void solve() throws IOException {
    int n = readInt(), m = readInt(), p = readInt();
    if (n < m) {//第一次都看不到
        printWriter.println(0);
    } else {
        printWriter.println(1 + (n - m) / p);
    }
}

B - Overlapping sheets

原题链接

题目描述
一个平面有N张矩形纸,求这些矩形纸能覆盖的面积

思路:模拟

public static void solve() throws IOException {
    int n = readInt();
    int[][] grid = new int[105][105];
    for (int i = 0; i < n; i++) {
        int a = readInt(), b = readInt(), c = readInt(), d = readInt();
        for (int p = a; p < b; p++) {
            for (int q = c; q < d; q++) {
                grid[p][q] = 1;
            }
        }
    }
    int s = 0;
    for (int i = 0; i < 105; i++) {
        for (int j = 0; j < 105; j++) {
            if (grid[i][j] == 1) s++;
        }
    }
    printWriter.println(s);
}

C - Blue Spring

原题链接

题目描述
高桥准备进行一场持续N天的旅行,每天的车票可以使用普通票,也可以使用一日通票。每天的普通票票价为 F i F_i Fi元,高桥也可以花P元购买D张一日通票,一日通票可以在任意一天使用。求最低消费

思路:排序

public static void solve() throws IOException {
    int n = readInt(), b = readInt(), p = readInt();
    int[] arr = utils.nextIntArray(n);
    Arrays.sort(arr, 1, n + 1);
    long sum = 0;
    for (int i = 1; i <= n; i++) sum += arr[i];
    int cur = n;
    for (; cur >= 1; cur--) {
        long curS = 0;//当前D张普通票票价之和
        int k = cur;
        for (; k > cur - b && k >= 1; k--) {
            curS += arr[k];
        }
        if (curS > p) {//如果>p,那么就用一日通票抵消
            sum -= curS; sum += p;
            cur = k + 1;
        } else {//否则终止
            break;
        }
    }
    printWriter.println(sum);
}

D - General Weighted Max Matching

原题链接

题目描述
给定一张带有N个顶点的带权无向图,要求选任意条边,且边连接的点没有被重复选过,求最大边权之和

思路:dfs

  • 由于点的个数较少,所以我们对于每一个点,枚举这个点选和不选的情况。
static int n, m;
static int[][] g;
static long res = 0;
static boolean[] match;

public static void solve() throws IOException {
    n = readInt();
    g = new int[n + 1][n + 1];
    match = new boolean[n + 1];
    for (int i = 1; i <= n - 1; i++) {
        for (int j = i + 1; j <= n; j++) {
            int a = readInt();
            g[i][j] = a; g[j][i] = a;
        }
    }
    dfs(1, 0);
    printWriter.println(res);

}

public static void dfs(int u, long sum) {
    if (u > n) {// 当所有点都被选过
        res = Math.max(res, sum);
        return;
    }
    for (int i = u + 1; i <= n; i++) {
        if (!match[u] && !match[i]) {// 两个点都没有被选过
            match[u] = match[i] = true;
            //注意是 u+1而不是 i+1,因为枚举的是 u的状态(选和不选)
            dfs(u + 1, sum + g[u][i]);// 满足条件,选当前点 u,并添加权值 g[u][i]
            match[u] = match[i] = false;
        }
    }
    dfs(u + 1, sum);// 当前点 u不选
}

E - Sandwiches

原题链接

题目描述
在一个长度为N的序列A中,找出满足以下条件的三元组的个数。

  • 1 ≤ i < j < k ≤ N , A i = A k , A i ≠ A j 1 \le i \lt j \lt k \le N, A_i = A_k, A_i \ne A_j 1i<j<kN,Ai=Ak,Ai=Aj

样例输入

9
4 2 4 2 4 4 2 4 2

样例输出

28

思路:组合数学

  • 首先存下每种数字出现的坐标集合,如果个数为1,则对答案没贡献,否则计算出两个相邻坐标i1i2有多少个元素(设为p),再计算出i1右边有多少个和它相同的数字(假设为r),并且计算出i2左边有多少个和它相同的数字(假设为l),那么总贡献为 p ∗ l ∗ r p * l * r plr
    AtCoder Beginner Contest 318 题解 A-E_第1张图片
    上面的 i指的是当前数字在坐标集合的下标(从0开始)
 public static void solve() throws IOException {
    int n = readInt();
    int[] arr = utils.nextIntArray(n);
    Map<Integer, List<Integer>> map = new HashMap<>();// 每一种数字的集合
    for (int i = 1; i <= n; i++) {
        // 如果 arr[i]的 value不存在则创建 ArrayList,如果存在则返回原来的 ArrayList
        map.computeIfAbsent(arr[i], g -> new ArrayList<>()).add(i);
    }
    long res = 0;
    for (List<Integer> indexes : map.values()) {
        int size = indexes.size();
        if (size == 1) continue;
        for (int i = 0; i < size - 1; i++) {
            long p = indexes.get(i + 1) - indexes.get(i) - 1;//两个相同的数字间有多少个不同的数字
            res += p * (i + 1) * (size - i - 1);
        }
    }
    printWriter.println(res);
}

你可能感兴趣的:(深度优先搜索dfs,技巧题,前后缀分解,深度优先,算法)