1 条题解

  • 0
    @ 2025-5-26 8:24:32

    题解:疯狂五数组合计数

    这道题要求我们在给定的序列中找出满足严格递增且位置递增的五元组数量。通过分析,我们可以使用树状数组(Binary Indexed Tree)结合动态规划来高效解决这个问题。

    方法思路

    1. 离散化处理:将原序列中的元素映射为排名,以便使用树状数组快速查询。
    2. 动态规划状态定义:dp[x][j] 表示前x个元素中,长度为j+1的递增子序列的数量。
    3. 树状数组优化:使用树状数组快速查询前缀和,加速状态转移过程。
    4. 大数处理:由于结果可能非常大,使用数组模拟大数加法。

    解决代码

    import sys
    
    class FenwickTree:
        def __init__(self, size):
            self.n = size
            self.tree = [0] * (self.n + 2)
        
        def update(self, idx, delta):
            while idx <= self.n:
                self.tree[idx] += delta
                idx += idx & -idx
        
        def query(self, idx):
            res = 0
            while idx > 0:
                res += self.tree[idx]
                idx -= idx & -idx
            return res
    
    def main():
        input = sys.stdin.read().split()
        ptr = 0
        while ptr < len(input):
            N = int(input[ptr])
            ptr += 1
            if ptr + N > len(input):
                break
            sequence = list(map(int, input[ptr:ptr+N]))
            ptr += N
            
            if N < 5:
                print(0)
                continue
            
            # 离散化处理
            sorted_unique = sorted(set(sequence))
            rank = {x: i+1 for i, x in enumerate(sorted_unique)}
            m = len(sorted_unique)
            
            # dp[k][i] 表示以第i个元素结尾的长度为k的递增子序列数量
            dp = [ [0] * N for _ in range(6) ]
            
            # 初始化长度为1的子序列
            for i in range(N):
                dp[1][i] = 1
            
            # 动态规划计算长度为2到5的子序列
            for k in range(2, 6):
                ft = FenwickTree(m)
                for i in range(N):
                    current_val = sequence[i]
                    r = rank[current_val]
                    # 查询所有比当前元素小的元素中,长度为k-1的子序列数量
                    count = ft.query(r - 1)
                    dp[k][i] = count
                    # 将当前元素的dp[k-1][i]加入树状数组
                    ft.update(r, dp[k-1][i])
            
            # 计算答案:所有长度为5的子序列数量之和
            print(sum(dp[5]))
    
    if __name__ == "__main__":
        main()
    

    代码解释

    1. 输入处理:读取输入数据并处理多个测试用例。
    2. 离散化处理:将原序列中的元素映射为排名,以便使用树状数组快速查询。
    3. 动态规划初始化:初始化dp[1][i]为1,表示每个元素自身构成一个长度为1的递增子序列。
    4. 动态规划状态转移:对于每个长度k从2到5,使用树状数组快速查询前缀和,更新dp[k][i]。
    5. 结果计算:累加所有长度为5的递增子序列的数量并输出。

    这种方法通过树状数组优化了动态规划的状态转移过程,将时间复杂度从O(N^2)降低到O(N log N),能够高效处理大规模数据。

    • 1

    信息

    ID
    2379
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者