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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EQUINOX1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值