# 第 274 场周赛题解

# Q1 2124. 检查是否所有 A 都在 B 之前 (opens new window)

硬模拟。

class SolutionA {
    fun checkString(s: String): Boolean {
        var meet = false
        s.forEach {
            if (it == 'b') meet = true
            if (it == 'a' && meet) return false
        }
        return true
    }
}
1
2
3
4
5
6
7
8
9
10

# Q2 2125. 银行中的激光束数量 (opens new window)

啥也不是,看题目还以为垂直方向也有啥限制... 一点思考都没有

class SolutionB {
    fun numberOfBeams(bank: Array<String>): Int {
        var lst = 0
        var cur = 0
        var ans = 0
        bank.map { it.count { it == '1' } }.filter { it != 0 }.forEach {
            lst = cur
            cur = it
            ans += lst * cur
        }
        return ans
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# Q3 2126. 摧毁小行星 (opens new window)

直接贪心,这期B、C都过水。

class SolutionC {
    fun asteroidsDestroyed(mass: Int, asteroids: IntArray): Boolean {
        var cur = mass.toLong()
        asteroids.sorted().forEach {
            if (it <= cur) {
                cur += it
            } else {
                return false
            }
        }
        return true
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# Q4 2127. 参加会议的最多员工数 (opens new window)

有意思,学到了新的知识!

每个点仅有一个出度,基环内向树。可参加的员工,要么是基环内向树中的环,要么是互相依赖的双节点及其两侧的最长链的总和。

  1. 先将环上的每个点的最长枝求出来,即环向外发射的部分(通过拓扑排序&DP一直把入度为1的都加完,环上的点入度至少为2)
  2. DFS求每个点的环,环深度为2,则可+两边的链长。
// 基环内向树
// 最大环 or 最长链
class SolutionD {
    fun maximumInvitations(favorite: IntArray): Int {
        val n = favorite.size
        val g = Graph(n)
        for (i in favorite.indices) {
            // 构造基环内向树
            g.addEdgeOri(favorite[i], i)
        }

        val (branch, isVisited) = g.getBranches()
//        branch.print()
        var ans = 0
        var tmp = 0
        // 计算每一个点作为起点时 环的长度 or 链的长度
        for (i in 0 until n) {
            if (isVisited[i]) continue
            var len = 0
            var u = i
            while (true) {
                val v = favorite[u]
                isVisited[u] = true
                len++
                if (isVisited[v]) break
                u = v
            }
            ans = if (len == 2) {
                // 二元环可以将两侧分支都带上
                tmp += 2 + branch[i] + branch[favorite[i]]
                maxOf(ans, tmp)
            } else {
                maxOf(ans, len)
            }
        }
        return ans
    }
}

// n为包含节点数
class Graph(val n: Int) {

    // 图中边(可以有方向)
    var adj: Array<LinkedList<Int>> = Array(n) { LinkedList<Int>() }

    // 图中边的权重(可以有方向)
    val weight = HashMap<Int, HashMap<Int, Int>>()

    init {
        for (i in 0 until n) {
            weight[i] = hashMapOf()
        }
    }

    fun addEdgeOri(i: Int, j: Int, w: Int = 0) {
        adj[i].add(j)
        weight[i]!![j] = w
    }

    fun addEdge(i: Int, j: Int, w: Int = 0) {
        // Add w to v's list.
        adj[i].add(j)
        // Add v to w's list
        adj[j].add(i)
        weight[i]!![j] = w
        weight[j]!![i] = w
    }
}

/**
 * 获取基环内向树各枝杈的最大长度
 *
 * @return 基环内向树各点的最大枝长度,属于枝的结点标记为true
 * */
fun Graph.getBranches(): Pair<IntArray, BooleanArray> {
    val indegree = IntArray(n)
    val isVisited = BooleanArray(n)
    val branches = IntArray(n)

    val dep = IntArray(n)

    // 基环内向树,每个点出度为1
    // 统计每个点的入度
    for (i in 0 until n) {
        indegree[i] = adj[i].size
        adj[i].forEach {
            dep[it] = i
        }
    }

    // 拓扑排序,先将入度为0的点入队
    val q: Queue<Int> = LinkedList<Int>()
    for (i in 0 until n) {
        if (indegree[i] == 0) {
            q.offer(i)
            isVisited[i] = true
        }
    }

    while (q.isNotEmpty()) {
        val u = q.poll()
        val v = dep[u]
        branches[v] = maxOf(branches[v], branches[u] + 1)
        if (--indegree[v] == 0) {
            q.offer(v)
            isVisited[v] = true
        }
    }

    return Pair(branches, isVisited)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111