1 条题解

  • 0
    @ 2026-3-30 20:56:43

    B. 水母与满天星 详细题解

    问题重述

    给定两个长度为nn的排列ppqq,元素均为[0,n1][0, n-1]的整数。需要计算数组rr,其中:

    $$r_i = \max_{j=0}^{i} \left( 2^{p_j} + 2^{q_{i-j}} \right) \quad \text{对于 } 0 \le i \le n-1 $$

    输出所有rir_i998244353998244353取模的结果。


    核心难点分析

    1. 如何快速比较2a+2b2^a + 2^b2c+2d2^c + 2^d

    直接计算幂次并比较数值可能超出整数范围,但注意到2k2^k在二进制表示中只有第kk位为11。因此:

    • a>ca > ca>da > d,则2a+2b>2c+2d2^a + 2^b > 2^c + 2^d
    • 比较两个形如2a+2b2^a + 2^b的数,等价于比较它们的二进制最高位
      • 首先比较最大值max(a,b)\max(a, b)max(c,d)\max(c, d)
      • 若最大值相等,再比较次大值

    2. 排列性质的作用

    题目强调ppqq是排列,这意味着:

    • 每个值00n1n-1pp中恰好出现一次
    • 每个值00n1n-1qq中恰好出现一次

    这个性质确保了:

    • 当我们遍历索引时,当前看到的ppqq的最大值会单调递增
    • 每个最大值只会在一个位置出现,便于跟踪

    算法核心思想

    前缀最大值跟踪

    定义:

    • ii = 当前已遍历的pp中最大值所在位置
    • jj = 当前已遍历的qq中最大值所在位置

    对于固定的kk,考虑所有j[0,k]j \in [0, k]

    • 表达式为2pj+2qkj2^{p_j} + 2^{q_{k-j}}

    关键引理

    对于任意kk,最大值一定出现在以下两种情况之一:

    1. 固定pp取当前最大值:取j=ij = i,得到2pi+2qki2^{p_i} + 2^{q_{k-i}}
    2. 固定qq取当前最大值:取j=kjj = k-j,得到2pkj+2qj2^{p_{k-j}} + 2^{q_j}

    证明:假设最大值由pap_aqbq_b贡献,且a+b=ka + b = k。若pap_a不是当前pp的最大值,则存在aka' \le k使得pa>pap_{a'} > p_a。那么取j=aj = a',得到2pa+2qka2^{p_{a'}} + 2^{q_{k-a'}}一定大于等于原值(第一项更大,第二项可能不同)。同理可证qq部分。因此,最大值必然可以由至少一个部分取当前最大值达到。


    算法流程

    设:

    • ii = 当前pp中最大值的位置
    • jj = 当前qq中最大值的位置

    遍历kk00n1n-1

    步骤 1:更新最大值位置

    • p[k]>p[i]p[k] > p[i],则i=ki = k
    • q[k]>q[j]q[k] > q[j],则j=kj = k

    步骤 2:根据p[i]p[i]q[j]q[j]的关系计算rkr_k

    情况 1:p[i]>q[j]p[i] > q[j] 此时p[i]p[i]是当前所有数中的最大值,因此最大值必定由p[i]p[i]贡献:

    rk=2p[i]+2qkir_k = 2^{p[i]} + 2^{q_{k-i}}

    情况 2:p[i]<q[j]p[i] < q[j] 此时q[j]q[j]是当前所有数中的最大值,因此最大值必定由q[j]q[j]贡献:

    rk=2q[j]+2pkjr_k = 2^{q[j]} + 2^{p_{k-j}}

    情况 3:p[i]=q[j]p[i] = q[j] 两个最大值相等,需要比较次大项:

    $$r_k = 2^{p[i]} + \max\left(2^{q_{k-i}}, 2^{p_{k-j}}\right) $$

    标程解析

    const int N = 1e5 + 5, Mod = 998244353;
    int n = 0, s[N] = {}, p[N] = {}, q[N] = {}, r[N] = {};
    
    int main(){
        // 预计算 $2^i \bmod MOD$
        s[0] = 1; 
        for(int i = 1 ; i < N ; i ++) 
            s[i] = s[i - 1] * 2 % Mod;
        
        scanf("%d", &T);
        while(T --) solve();
        return 0;
    }
    

    预计算数组ss[i]存储2imod9982443532^i \bmod 998244353,避免重复计算。

    inline void solve(){
        scanf("%d", &n);
        for(int i = 0 ; i < n ; i ++) scanf("%d", &p[i]);
        for(int i = 0 ; i < n ; i ++) scanf("%d", &q[i]);
        
        for(int i = 0, j = 0, k = 0 ; k < n ; k ++){
            // 更新当前最大值的位置
            if(p[k] > p[i]) i = k; 
            if(q[k] > q[j]) j = k;
            
            // 根据情况计算 $r_k$
            if(p[i] != q[j]){
                if(p[i] > q[j]) 
                    printf("%d ", (s[p[i]] + s[q[k - i]]) % Mod);
                else 
                    printf("%d ", (s[q[j]] + s[p[k - j]]) % Mod);
            }
            else 
                printf("%d ", (s[p[i]] + s[max(q[k - i], p[k - j])]) % Mod);
        }
        printf("\n");
    }
    

    关键点

    • ij始终指向当前已遍历元素中ppqq的最大值位置
    • 对于每个kk,只需计算常数个候选值,无需遍历所有jj
    • 利用排列性质确保最大值单调递增,无需回退

    正确性证明

    定理:对于任意kk,上述算法计算的rkr_k等于maxj=0k(2pj+2qkj)\max_{j=0}^{k} (2^{p_j} + 2^{q_{k-j}})

    证明:由引理可知,最大值必然可以由以下两种形式之一达到:

    1. j=ij = i,其中iipp当前最大值的下标
    2. j=kjj = k-j,其中jjqq当前最大值的下标

    算法考虑了这两种情况:

    • p[i]q[j]p[i] \neq q[j]时,较大的那个一定是全局最大值,因此只需考虑对应的一种情况
    • p[i]=q[j]p[i] = q[j]时,两种情况的第一个加数相等,只需比较第二个加数取最大值

    因此算法正确。


    时间复杂度分析

    • 预处理ss数组:O(N)O(N),其中N=105N = 10^5
    • 每个测试用例:O(n)O(n)
    • 总复杂度:O(n+N)O(2×105)O(\sum n + N) \le O(2 \times 10^5),完全可行

    示例验证

    以第一个测试用例为例:

    • p=[0,2,1]p = [0, 2, 1]q=[1,2,0]q = [1, 2, 0]

    遍历过程:

    k=0k = 0

    • 初始:i=0,j=0i = 0, j = 0
    • 更新后:i=0,j=0i = 0, j = 0
    • p[i]=0p[i] = 0q[j]=1q[j] = 1p[i]<q[j]p[i] < q[j]
    • r0=2q[0]+2p[0]=21+20=2+1=3r_0 = 2^{q[0]} + 2^{p[0]} = 2^1 + 2^0 = 2 + 1 = 3

    k=1k = 1

    • 更新:p[1]=2>p[0]=0p[1] = 2 > p[0] = 0i=1i = 1q[1]=2>q[0]=1q[1] = 2 > q[0] = 1j=1j = 1
    • p[i]=2p[i] = 2q[j]=2q[j] = 2,相等
    • $r_1 = 2^{p[1]} + \max(2^{q[1-1]}, 2^{p[1-1]}) = 2^2 + \max(2^{q[0]}, 2^{p[0]}) = 4 + \max(2, 1) = 6$

    k=2k = 2

    • i=1,j=1i = 1, j = 1保持不变
    • p[i]=2p[i] = 2q[j]=2q[j] = 2,相等
    • $r_2 = 4 + \max(2^{q[1]}, 2^{p[1]}) = 4 + \max(4, 4) = 8$

    输出:3 6 83\ 6\ 8,与题目示例一致。

    • 1

    信息

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