2836. 在传球游戏中最大化函数值

Powered by:NEFU AB-IN

Link

2836. 在传球游戏中最大化函数值

题意

给你一个长度为 n 下标从 0 开始的整数数组 receiver 和一个整数 k 。

总共有 n 名玩家,玩家 编号 互不相同,且为 [0, n - 1] 中的整数。这些玩家玩一个传球游戏,receiver[i] 表示编号为 i 的玩家会传球给编号为 receiver[i] 的玩家。玩家可以传球给自己,也就是说 receiver[i] 可能等于 i 。

你需要从 n 名玩家中选择一名玩家作为游戏开始时唯一手中有球的玩家,球会被传 恰好 k 次。

如果选择编号为 x 的玩家作为开始玩家,定义函数 f(x) 表示从编号为 x 的玩家开始,k 次传球内所有接触过球玩家的编号之 和 ,如果有玩家多次触球,则 累加多次 。换句话说, f(x) = x + receiver[x] + receiver[receiver[x]] + … + receiverk

你的任务时选择开始玩家 x ,目的是 最大化 f(x) 。

请你返回函数的 最大值 。

注意:receiver 可能含有重复元素。

思路

倍增的板子题,也是一个稍微的变种,加了一个需求,求路径上的节点和,这个在倍增的时候利用元组维护即可
pa[x][i + 1] 路径s就由两部分组成,自己到父亲的距离,父亲到父亲的父亲的距离

  1. 这个题不需要判断是否有父节点,因为这个图有环,且每个点都有父节点
  2. 利用倍增算法,预处理每个节点 x 的第 2^i个祖先节点,以及从 x 的父节点到 x 的第 2^i个祖先节点的节点编号之和。最后枚举起点 x,一边向上跳一边累加节点编号。

https://leetcode.cn/problems/maximize-value-of-function-in-a-ball-passing-game/solutions/2413298/shu-shang-bei-zeng-by-endlesscheng-xvsv/

代码

'''
Author: NEFU AB-IN
Date: 2024-07-27 10:24:54
FilePath: \LeetCode\2836\2836.py
LastEditTime: 2024-07-27 11:48:47
'''
# 3.8.19 import
import random
from collections import Counter, defaultdict, deque
from datetime import datetime, timedelta
from functools import lru_cache
from heapq import heapify, heappop, heappush, nlargest, nsmallest
from itertools import combinations, compress, permutations, starmap, tee
from math import ceil, comb, fabs, floor, gcd, hypot, log, perm, sqrt
from string import ascii_lowercase, ascii_uppercase
from sys import exit, setrecursionlimit, stdin
from typing import Any, Dict, List, Optional, Tuple, TypeVar, Union

# Constants
TYPE = TypeVar('TYPE')
N = int(2e5 + 10)
M = int(20)
INF = int(1e12)
OFFSET = int(100)
MOD = int(1e9 + 7)

# Set recursion limit
setrecursionlimit(int(2e9))


class Arr:
    array = staticmethod(lambda x=0, size=N: [x() if callable(x) else x for _ in range(size)])
    array2d = staticmethod(lambda x=0, rows=N, cols=M: [Arr.array(x, cols) for _ in range(rows)])
    graph = staticmethod(lambda size=N: [[] for _ in range(size)])


class Math:
    max = staticmethod(lambda a, b: a if a > b else b)
    min = staticmethod(lambda a, b: a if a < b else b)


class IO:
    input = staticmethod(lambda: stdin.readline().rstrip("\r\n"))
    read = staticmethod(lambda: map(int, IO.input().split()))
    read_list = staticmethod(lambda: list(IO.read()))


class Std:
    class TreeAncestor:
        """
        Binary Lifting for Tree Ancestor Queries, allows us to find the 2^i-th ancestor of any node.
        Ensure that each node has only one edge pointing to another node to apply binary lifting.
        """

        def __init__(self, n: int, m: int, parent: List[int]):
            """
            Initializes the TreeAncestor with the given number of nodes and parent list.

            Args:
                n (int): Number of nodes.
                m (int): Maximum power of 2 to consider (default calculated based on n).
                parent (List[int]): List where parent[i] is the parent of node i.
            """
            # m = n.bit_length() - 1
            self.n = n
            self.m = m
            pa = [[(p, p)] + Arr.array((-1, -1), m) for p in parent]  # pa[i][0] = p
            for i in range(m):
                for x in range(n):
                    p, s = pa[x][i]  # Get the 2^i-th ancestor of node x
                    pp, ss = pa[p][i]  # Get the 2^i-th ancestor of p, which will be the 2^(i+1)-th ancestor of x
                    pa[x][i + 1] = (pp, ss + s)  # Set the 2^(i+1)-th ancestor of x
            self.pa = pa


# ————————————————————— Division line ——————————————————————
class Solution:
    def getMaxFunctionValue(self, receiver: List[int], k: int) -> int:
        ta = Std.TreeAncestor(len(receiver), k.bit_length() - 1, receiver)
        ans = 0
        for i in range(ta.n):
            sum_ = i
            node = i
            for j in range(ta.m + 1): # ta.m + 1 = k.bit_length(), 枚举k的每一位
                if (1 << j) & k:
                    node, s = ta.pa[node][j]
                    sum_ += s
            ans = Math.max(ans, sum_)
        return ans

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

NEFU AB-IN

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

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

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

打赏作者

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

抵扣说明:

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

余额充值