Bootstrap

LeetCode 第414场周赛个人题解

目录

Q1. 将日期转换为二进制表示

原题链接

思路分析

AC代码

Q2. 范围内整数的最大得分

原题链接

思路分析

AC代码

Q3. 到达数组末尾的最大得分

原题链接

思路分析

AC代码

Q4. 吃掉所有兵需要的最多移动次数

原题链接

思路分析

AC代码


Q1. 将日期转换为二进制表示

原题链接

Q1. 将日期转换为二进制表示

思路分析

签到题

AC代码

class Solution:
    def convertDateToBinary(self, date: str) -> str:
        date = date.split('-')
        date = [bin(int(x))[2::] for x in date]
        return '-'.join(date)


 

Q2. 范围内整数的最大得分

原题链接

Q2. 范围内整数的最大得分

思路分析

二分

最大化最小,可以二分

二分答案x,那么如何check?

贪心的往左边放,第一个放0,那么下一个至少要放到0 + x,下一个的位置为max(0 + x, start[1])

以此类推

时间复杂度:O(nlogU)

AC代码

class Solution:
    def maxPossibleScore(self, start: List[int], d: int) -> int:
        start.sort()
        
        def check(x: int) -> bool:
            pre = start[0]
            for i in range(1, len(start)):
                pre = max(pre + x, start[i])
                if pre > start[i] + d:
                    return False
            return True

        lo, hi = 0, start[-1] + d
        res = -1
        while lo <= hi:
            x = (lo + hi) // 2
            if check(x):
                res = x
                lo = x + 1
            else:
                hi = x - 1

        return res

Q3. 到达数组末尾的最大得分

原题链接

Q3. 到达数组末尾的最大得分

思路分析

李超线段树秒杀斜率优化dp

写一个暴力的dp方程

定义状态 f(i) 为跳到 i 的最大收益

那么 f(i) = min{ f(j) + (i - j) * nums[j] }

f(i) = f(j) + i * nums[j] - j * nums[j]

令 y = f(i), k = nums[j], b = - j * nums[j]

每次插入一条线段,每次状态转移看作 x = i 处 所有线段最高点

时间复杂度:O(nlogn)

AC代码

using i64 = long long;

const int N = 2e5 + 10;
constexpr i64 inf64 = 1E18 + 7;

struct line {
    i64 k, b;
} lines[N];

inline i64 gety(int id, int x) {
    return lines[id].k * x + lines[id].b;
}

int tr[N << 2];

#define lc p << 1
#define rc p << 1 | 1
void update(int p, int l, int r, int id) {
    int mid = l + r >> 1;
    if (gety(id, mid) > gety(tr[p], mid)) std::swap(tr[p], id);
    if (gety(id, l) > gety(tr[p], l)) update(lc, l, mid, id);
    if (gety(id, r) > gety(tr[p], r)) update(rc, mid + 1, r, id);
}

i64 query(int p, int l, int r , int x) {
    if (l == r) return gety(tr[p], x);
    int mid = l + r >> 1;
    i64 res = gety(tr[p], x);
    if (x <= mid) return std::max(res, query(lc, l, mid, x));
    return std::max(res, query(rc, mid + 1, r, x));
}
class Solution {
public:
    long long findMaximumScore(vector<int>& a) {
        memset(tr, 0, sizeof tr);
        int n = a.size();
        std::vector<i64> f(n);
        lines[0] = { a[0], 0 };
        for (int i = 1; i < n; ++ i) {
            f[i] = query(1, 0, N - 1, i);
            lines[i] = { a[i], f[i] - 1LL * i * a[i] };
            update(1, 0, N - 1, i);
        }
        return f[n - 1];
    }
};

Q4. 吃掉所有兵需要的最多移动次数

原题链接

Q4. 吃掉所有兵需要的最多移动次数

思路分析

博弈dp & 状压dp

网格很小,国际象棋不会下,那么就bfs暴力处理每个点开始,到其它点的距离

定义状态 f(cx, cy, st, turn) 代表 玩家从 (cx, cy) 出发,已经遍历过的马的集合为st,turn代表

0:Alice,1:Bob

那么 我们枚举当前玩家要到的马的位置(x, y)

对于Alice:

res = max(res, w + dfs(x, y, nst, turn ^ 1))

对于Bob:

res = min(res, w + dfs(x, y, nst, turn ^ 1))

时间复杂度:O(2500 * 2500 + n^2 * (1 << n))

AC代码

B = 50

dir = [
    (-2, -1), (-2, 1), (2, -1), (2, 1),
    (-1, -2), (-1, 2), (1, -2), (1, 2)
]

def get(kx, ky):
    d = [[inf] * B for _ in range(B)]
    q = deque([(kx, ky)])
    d[kx][ky] = 0

    while q:
        x, y = q.popleft()
        for dx, dy in dir:
            nx, ny = x + dx, y + dy
            if 0 <= nx < B and 0 <= ny < B and d[nx][ny] == inf:
                d[nx][ny] = d[x][y] + 1
                q.append((nx, ny))

    return d

d = [get(i, j) for i in range(B) for j in range(B)]

class Solution:
    def maxMoves(self, kx: int, ky: int, positions: List[List[int]]) -> int:
        n = len(positions)

        @cache
        def dfs(cx, cy, st: int, turn: int) -> int:
            if st == (1 << n) - 1:
                return 0
            id = cx * B + cy
            res = inf if turn else -inf
            for i, (x, y) in enumerate(positions):
                if ((st >> i) & 1) == 0:
                    w = d[id][x][y]
                    nst = st | (1 << i)
                    if turn:
                        res = min(res, w + dfs(x, y, nst, turn ^ 1))
                    else:
                        res = max(res, w + dfs(x, y, nst, turn ^ 1))
            return res
        dfs.cache_clear()

        return dfs(kx, ky, 0, 0)

;