前置知识

ST 表

题意简述

给定一个长度为 nn 的序列 vv。初始时,i{1,2,,n},vi=1\forall i\in\{1,2,\dots,n\},v_i=1。可执行以下操作:

选定一个 i{1,2,,n}i\in\{1,2,\dots,n\}。然后:

  • aia_i 的代价,j{1,2,,i}\forall j\in \{1,2,\dots,i\},令 vj0v_j\leftarrow0

  • bib_i 的代价,令 vi0v_i\leftarrow0

  • cic_i 的代价,令 vi1v_i\leftarrow1

qq 次询问,每次询问给定集合 PP,求使得序列 vv 满足

$$\forall i\in\{1,2,\dots,n\},v_i=\begin{cases} 0,i\not\in P\\ 1,i\in P \end{cases}$$

最小总代价

每次询问相互独立

数据范围

1n,m5×1051 \leqslant n,\sum m \leqslant 5\times 10^50mn0\leqslant m \leqslant n1qmax(n,m)1\leqslant q\leqslant \max(n,\sum m)0ai,bi,ci1090 \leqslant a_i, b_i, c_i \leqslant 10^91pin1\leqslant p_i \leqslant n

测试点编号 nn \leqslant mm m\sum m cic_i
121 \sim 2 5×1055 \times 10^5 =0=0 109\leqslant10^9
343 \sim 4 77 7\leqslant7 15 \leqslant15
565 \sim 6 20002000 1\leqslant1 2000 \leqslant2000
77 2000\leqslant2000 =0=0
8118 \sim 11 2000 \leqslant2 000 109\leqslant10^9
121312 \sim 13 5×1045 \times 10^4 5×104\leqslant5 \times 10^4 5×104 \leqslant5 \times 10^4
141514 \sim 15 5×1055 \times 10^5 1\leqslant1 5×105 \leqslant5 \times 10^5
1616 5×105\leqslant5 \times 10^5 =0=0
172017 \sim 20 109\leqslant10^9

解题思路

测试点 121\sim2

做法

这里令 a0=0a_0=0,则答案为

$$\displaystyle\min_{i=0}^n\{a_i+\displaystyle\sum_{j=i+1}^nb_i\} $$

正确性证明

$m=0\implies P=\varnothing\implies\forall i\in\{1,2,\dots,n\},i\not\in P\implies$ 在最终的序列 vv 中,i{1,2,,n},vi=0\forall i\in\{1,2,\dots,n\},v_i=0

因此,我们不可能将 viv_i 赋值为 11只可能以 aia_ibib_i 代价将序列赋值为 00

设我们 bib_i 的代价单独 赋值为 00 的所有 下标 构成的集合为 AA。设 AA 中最小的元素为 dd,若 i{d+1,d+2,,n},i∉A\exists i\in\{d+1,d+2,\dots,n\},i\not\in A,则我们必然需要花费 aia_i 的代价,将 vi0v_i\leftarrow0。此时,我们同时也使得 i{1,2,,i},vi=0\forall i\in\{1,2,\dots,i\},v_i=0,若不花费 bdb_d 的代价,也能达成这一效果,因此 至少 bdb_d 的花费是不必要的,即该条件下的方案 一定不优

因此得证:若对元素 单独 赋值为 00,则必然有 i{d,d+1,d+2,,n},iA\forall i\in\{d,d+1,d+2,\dots,n\},i\in A,其中 ddAA 的含义同上。也就是说,在最优方案中,单独赋值为 00 的下标必然构成序列下标的一段后缀

此时还需要对 v1,v2,,viv_1,v_2,\dots,v_i 全体元素 赋值为 00。若 id1i\not=d-1,则必然需要花费 ad1a_{d-1} 的代价将 d1d-1 之前的元素赋值为 00,此时 aia_i 的花费是不必要的,即该条件下的方案 一定不优

因此得证:只有花费 ad1a_{d-1} 的代价将 v1,v2,,vd1v_1,v_2,\dots,v_{d-1} 全体赋值为 00,才可能成为最优方案

综上所述,将所有可能成为最优方案的方案再取最优,即为问题的答案:

$$\displaystyle\min_{i=0}^n\{a_i+\displaystyle\sum_{j=i+1}^nb_i\} $$

因而思路正确。

具体实现

预处理 bib_i后缀和。分别枚举使用 aia_i 代价与使用 bib_i 代价的分界点,计算对应总代价,不断更新答案。

最终对于每个询问,输出这个答案。

时间复杂度分析

处理后缀和,复杂度 O(n)O(n)。枚举分界点时,由于此时后缀和可 O(1)O(1) 求,因此总复杂度也为 O(n)O(n)

对于所有的询问输出答案,复杂度 O(q)O(q)

总时间复杂度 O(n+q)O(n+q),可以通过 测试点 121\sim2

参考核心代码

for(i=n;i>=1;i--)
    sumb[i]=sumb[i+1]+1ll*b[i];//计算b数组的后缀和
long long ans=INF;
for(i=0;i<=n;i++)
    ans=min(ans,a[i]+sumb[i+1]);//计算每个总代价,更新答案
int q=R();
while(q--){
    int m=R();
    printf("%lld\n",ans);//对于每个询问,输出答案
}

期望得分

1010 分。

测试点 343\sim4

做法

令初始的所有 vi=1v_i=1

对于每一个位置 ii分别枚举 以下情况:

  • 使用 aia_i 的代价,将 v1,v2,,viv_1,v_2,\dots,v_i 全部赋值为 00,并将 v1,v2,,viv_1,v_2,\dots,v_i 中应当在最终序列中为 11 的所有元素 vjv_j,使用对应的 cjc_j 代价将其赋值为 11

  • 使用 bib_i 的代价,将 vi0v_i\leftarrow0

  • 使用 cic_i 的代价,将 vi1v_i\leftarrow1

  • 不做任何操作。

并继续向下 搜索,直到所有位置的操作都确定完。当所有位置操作做完后,判断当前序列是否与应当的最终序列相同。若不相同,则不合题意;若相同,则更新答案。

这样即可得到最终的答案。

正确性证明

考虑序列的第 ii 个位置。

若使用上述第一种操作中,用 aia_i 代价将 v1,v2,,viv_1,v_2,\dots,v_i 全部赋值为 00,则只有使用上述的 cj\sum c_j 代价将前面应当赋值为 11 的元素全部赋值为 11,才能保证当前序列是符合题意的序列。若其中含有其他操作,由于可以只使用 cj\sum c_j 代价进行赋值为 11 的操作,因此这些 其他操作一定是不必要的

故:使用 aia_i 代价将 v1,v2,,viv_1,v_2,\dots,v_i 全部赋值为 00 和使用 cj\sum c_j 代价将应当赋值为 11 的元素全部赋值为 11,这两个操作是 捆绑的

对于该位置,也可以做上述的第二、三、四种操作。除此之外,再无别的操作。

因此,我们考虑到了 所有可能符合题意的操作,并从中筛选出了 所有真正符合题意的操作,并取最小答案。所以,这一思路是正确的。

具体实现

使用 深度优先搜索(DFS)实现。

对于每个询问,记 DFS(now,cost)DFS(now,cost) 表示搜索到了 nownow 位置,当前的所有操作代价总和为 costcost。则枚举该位置的四种情况:

Δ\Delta 表示该位置的一种操作产生的 costcost 增加量。

  • 第一种情况:$\Delta=a_{now}+\displaystyle\sum_{i=1}^{now}[i\in P]c_i$。

  • 第二种情况:Δ=bnow\Delta=b_{now}

  • 第三种情况:Δ=cnow\Delta=c_{now}

  • 第四种情况:Δ=0\Delta=0

继续向下执行 DFS(now+1,cost+Δ)DFS(now+1,cost+\Delta) 即可。注意在枚举对应情况时,需要对序列对应元素 及时赋值。为了便于 回溯,可以在函数内部再开一个数组,记录 赋值前序列的前 nownow 个元素

now=n+1now=n+1 时,首先判断当前序列是否与应当得到的最终序列相同。若不同,直接返回;否则,更新答案。

最后输出答案。

时空复杂度分析

时间复杂度:由于对每个位置需要枚举 44 种情况,每次枚举的复杂度为 O(n)O(n),因此对每个询问,总复杂度为 O(n4n)O(n4^n)

总时间复杂度 O(4nqn)O(4^nqn),可以通过 测试点 343\sim4

空间复杂度:在 DFS 中,递归的最大层数为 O(n)O(n) 级别,且每层需要新开一个大小为 O(n)O(n) 的临时数组。

空间复杂度为 O(n2)O(n^2),可以通过 测试点 343\sim4

参考核心代码

void DFS(int now,long long cost){
    if(now==n+1){//如果已经确定所有位置的操作
        for(int i=1;i<=n;i++)
            if(tmp[i]!=fnl[i])//判断当前序列是否符合题意,若不符合直接返回
                return;
        ans=min(ans,cost);//否则更新答案
        return;
    }
    long long delta=a[now];//cost增加量
    vector<int>tmp1(now+1);
    for(int i=1;i<=now;i++)
        tmp1[i]=tmp[i];//临时数组,记录赋值前序列
    for(int i=1;i<=now;i++)
        tmp[i]=0;
    for(int i=1;i<=m;i++){
        if(p[i]>now)
            break;
        delta+=c[p[i]];
        tmp[p[i]]=1;//第一种情况
    }
    DFS(now+1,cost+delta);//向下继续搜索
    for(int i=1;i<=now;i++)
        tmp[i]=tmp1[i];//回溯
    tmp[now]=0;
    delta=b[now];
    DFS(now+1,cost+delta);//第二种情况
    tmp[now]=tmp1[now];//回溯
    tmp[now]=1;
    delta=c[now];
    DFS(now+1,cost+delta);//第三种情况
    tmp[now]=tmp1[now];//回溯
    DFS(now+1,cost);//第四种情况
}
...
        fill(tmp+1,tmp+1+n,1);//初始v[i]=1
        fill(fnl+1,fnl+1+n,0);
        for(i=1;i<=m;i++)
            fnl[p[i]]=1;//设定最终序列
        ans=INF;
        DFS(1,0);
        printf("%lld\n",ans);//输出答案

期望得分

1010 分。结合 测试点 121\sim2 的算法可以获得 2020 分。

测试点 565\sim6

做法

a0=0a_0=0。当 m=1m=1 时,对于每个询问,其答案为

$$\min(\displaystyle\min_{i=0}^{p_1-1}\{a_i+\displaystyle\sum_{j=i+1}^{p_1-1}b_j+\displaystyle\sum_{j=p_1+1}^nb_j\},\displaystyle\min_{i=p_1}^n\{a_i+\displaystyle\sum_{j=i+1}^nb_j+c_{p_1}\}) $$

m=0m=0 时的答案与 测试点 121\sim2 中相同。

正确性证明

对于所有的询问,m=1    m=1\implies 最终序列中只有一个位置 p1p_1 满足 vp1=1v_{p_1}=1,其他位置 ii 都有 vi=0v_i=0

考虑对序列除 p1p_1 位置外的所有位置赋 00 的方式。由 测试点 121\sim2 的证明,对于最终为全 00 的序列,最优方案使用 aia_i 的代价 最多一次。并且,使用 bib_i 代价赋值的所有下标必然构成 一段后缀

现尝试将该结论迁移到 m=1m=1 的情况。若在 p1p_1 下标前的 ii 使用了一次 aia_i 代价,则在 ii 后面的位置 jj,再使用一次 aja_j,也 一定是不优的,证法类似。若使用 bib_i 的下标 ii 中,存在位置 jj 满足最终 vj=0v_j=0 且未使用 bjb_j,则必然使用 aja_j,则该情况回到了 测试点 121\sim2,必然不优,所有其他位置 jj 必然使用一次 bjb_j

因此,测试点 121\sim2 的结论在此处 仍然基本成立

考虑在 p1p_1 下标及其后面下标 ii 处使用 aia_i 的情况。此时根据上述推理,必然在 i+1,i+2,,ni+1,i+2,\dots,n 处使用 bib_i。由于最终需要使得 vp1=1v_{p_1}=1,因此还需要 使用一次 cp1c_{p_1},才能符合题意,不需要再使用其他操作。

因此上述答案得证。

具体实现

对于 m=1m=1

预处理 bb 数组的前缀和 sumbsumb,则 i=lrbi=sumbrsumbl1\displaystyle\sum_{i=l}^rb_i=sumb_r-sumb_{l-1}

处理每次询问时,扫一遍序列,按照上述计算式计算即可。

也可以使用 sumbnsumbibp1sumb_n-sumb_i-b_{p_1} 代替 $\displaystyle\sum_{j=i+1}^{p_1-1}b_j+\displaystyle\sum_{j=p_1+1}^nb_j$。

扫完整个序列之后输出答案即可。

时间复杂度分析

处理前缀和,复杂度 O(n)O(n)。每次回答询问时,需要扫一遍序列,单次回答复杂度 O(n)O(n)

总时间复杂度 O(qn)O(qn),可以通过 测试点 565\sim6

参考核心代码

以下代码略去了 m=0m=0 的情况。

...//预处理b数组前缀和
    for(i=0;i<p[1];i++)//计算前半部分答案
        ans=min(ans,a[i]+sumb[n]-sumb[i]-b[p[1]]);
    for(i=p[1];i<=n;i++)//计算后半部分答案
        ans=min(ans,a[i]+sumb[n]-sumb[i]+c[p[1]]);
    printf("%lld\n",ans);//输出答案

期望得分

1010 分。结合 测试点 121\sim2 的算法可以获得 2020 分,结合 测试点 343\sim4 的算法可以获得 2020 分,结合 测试点 141\sim4 的算法可以获得 3030 分。(1)(1)

测试点 77

做法

a0=0a_0=0。则对于每个询问,其答案为

$$\displaystyle\min_{i=0}^n\{a_i+\displaystyle\sum_{j=i+1}^n[j\not\in P]b_j\} $$

正确性证明

根据 测试点 343\sim4 的推理,我们知道,将 v1,v2,,viv_1,v_2,\dots,v_i 全部赋值为 00 的操作,往往和将所有 jP,j{1,2,,i}j\in P,j\in\{1,2,\dots,i\}vj1v_j\leftarrow1 的操作是 捆绑的

并且由于 ci=0c_i=0,因此我们 可以无视 赋值为 11 的代价,只需要考虑 aia_ibib_i 即可。

根据 测试点 121\sim2 的推理,若分别使用一次 ai,aja_i,a_j,这样的 总代价一定是更大的。因此,aia_i 最多只可能使用一次。确定 aia_i 使用位置后,只需要在其后面使用 bib_i 将对应位置 vi0v_i\leftarrow0。同时,由于 m1m\geqslant1,为尽可能 最小化总代价,只对最终序列中所有 vi=0v_i=0 的位置 ii 使用 bib_i 的代价即可。这些位置的代价是 必须使用不可替代 的,若在其他位置使用其他代价,则都是不必要的。

我们证明了在这些答案中一定能够取到所有合法总代价的 下界,因此该思路是正确的。

具体实现

对于每一次询问,处理一个 后缀和 数组:sumi=j=in[i∉P]bisum_i=\displaystyle\sum_{j=i}^n[i\not\in P]b_i

然后,扫一遍序列,按照上式计算即可。

最后输出答案。

时间复杂度分析

对于每次询问,需要处理后缀和数组,复杂度 O(n)O(n);扫一遍序列并计算,复杂度 O(n)O(n)

总时间复杂度 O(qn)O(qn)。根据该解法,可以通过 测试点 12,71\sim2,7

参考核心代码

    for(i=1;i<=m;i++)
        fnl[p[i]]=1;//设定最终序列
    for(i=n;i>=1;i--)
        sumb1[i]=sumb1[i+1]+b[i]*(!fnl[i]);//求b的上述后缀和
    for(i=0;i<=n;i++)
        ans=min(ans,a[i]+sumb1[i+1]);//根据上式计算答案
    printf("%lld\n",ans);//输出答案

期望得分

1515 分。结合 测试点 343\sim4 的算法可以获得 2525 分,结合 测试点 565\sim6 的算法可以获得 2525 分,结合测试点 363\sim6 的算法可以获得 3535 分。(2)(2)

测试点 8118\sim11

做法

对于每个询问,设 dpidp_i 表示考虑将序列 [1,pi][1,p_i] 变为合法序列的 最小总代价。则

$$dp_i=\min(\displaystyle\min_{j=p_{i-1}+2}^{p_i}\{a_j+\displaystyle\sum_{k=1}^{p_{i-1}}[k\in P]c_k+\displaystyle\sum_{k=j}^{p_i-1}b_k\},dp_{i-1}+\displaystyle\sum_{k=p_{i-1}+1}^{p_i-1}b_k,a_{p_i}+\displaystyle\sum_{k=1}^{p_i}[k\in P]c_k) $$

对于每个询问,令 pm+1=n+1p_{m+1}=n+1,且计算 dpm+1dp_{m+1} 时的上述式子 不包含第三项,则答案为 dpm+1dp_{m+1}

正确性证明

根据前面几个测试点的推理,我们注意到,将一段 区间全部赋值为 00 已成为 重要的子问题。由于 i{1,2,,m1},pi<pi+1\forall i\in\{1,2,\dots,m-1\},p_i\lt p_{i+1},因此我们在考虑到 pip_i 时,j{pi1+1,pi1+2,,pi1}\forall j\in\{p_{i-1}+1,p_{i-1}+2,\dots,p_i-1\},都需要使得最终序列的 vj=0v_j=0,且 pi1p_{i-1} 及前面的最小代价已知。

现考虑所有可能将该区间全部赋值为 00 的方案:

  • 对于一个 j{pi1+1,pi1+2,,pi1}j\in\{p_{i-1}+1,p_{i-1}+2,\dots,p_i-1\},使用 aja_j 的代价,将 v1,v2,,vjv_1,v_2,\dots,v_j 全部赋值为 00。此后需要立即执行 k{1,2,,j},kP,vk1\forall k\in\{1,2,\dots,j\},k\in P,v_k\leftarrow1 的操作(具体原因见 测试点 343\sim4),并将位置 jjpi1p_i-1 这段后缀中每个位置 kk,全部用 bkb_k 的代价赋值为 00aja_j 不可能在不同位置使用多次,原因见 测试点 12,561\sim2,5\sim6 等,这里不再赘述。

  • 对于该区间的所有位置 ii,使用 bib_i 代价,将 vi0v_i\leftarrow0。由于该操作 基于 pi1p_{i-1} 及前面已经操作好的序列,因此需要将该代价与 dpi1dp_{i-1} 累加

  • pip_i 位置使用 apia_{p_i} 代价,将 v1,v2,,vpiv_1,v_2,\dots,v_{p_i} 全部赋值为 00,再 $\forall k\in\{1,2,\dots,p_i\},k\in P,v_k\leftarrow1$。该操作其实与第一个操作类似,但赋值为 11 的元素多了一个 vpiv_{p_i}

bib_i 代价使用的下标不构成 {1,2,,pi1}\{1,2,\dots,p_i-1\} 的一段后缀,则该方案 一定不优,具体已在 测试点 12,561\sim2,5\sim6 中证明。

由于已知最终序列中 vpi=1v_{p_i}=1,因此若使用 bpib_{p_i} 代价,单独将 vpi0v_{p_i}\leftarrow0,则该操作必然是 多余的

综上,我们已经考虑到了此时所有可能的最优情况。

对于 dpm+1dp_{m+1},由于实际上不存在 n+1n+1 位置的元素,因此只能将 vpm,vpm+1,,vnv_{p_m},v_{p_m+1},\dots,v_n 全部赋值为 00,故其计算式中只有前两项。

因此,我们考虑完了 整个序列 的所有可能最优情况,故该思路是正确的。

具体实现

预处理 bb 的前缀和 sumbsumb

对于每次询问,在枚举每个 pip_i 时,先扫 pi1+2p_{i-1}+2pip_i,计算前两项更新 dpdp 值,再 动态更新 j=1pi[jP]cj\displaystyle\sum_{j=1}^{p_i}[j\in P]c_j。具体地,在每次计算完式中前两项后,直接将 cpic_{p_i} 加入该询问的 sumcsumc。然后,计算第三项,更新 dpdp 值。

扫完每个 pip_i 后,输出 dpm+1dp_{m+1}。注意 dpm+1dp_{m+1} 的计算中 没有第三项

时间复杂度分析

预处理 sumbsumb,复杂度为 O(n)O(n)。处理每次询问,扫的范围 刚好覆盖了整个序列,因此复杂度为 O(n)O(n)。扫 pip_i 以及动态更新 sumcsumc,复杂度 O(m)O(m)

总时间复杂度 O(qn)O(qn)。根据该解法,可以通过 测试点 3113\sim11

参考核心代码

    p[m+1]=n+1;//边界条件
    long long sumc=0;//每次询问动态更新在P中i的c[i]总和
    for(i=1;i<=m+1;i++){
        dp[i]=INF;
        for(j=p[i-1]+1;j<=p[i]-1;j++)
            dp[i]=min(dp[i],sumc+a[j]+sumb[p[i]-1]-sumb[j]);//式子中的第一项
        dp[i]=min(dp[i],sumb[p[i]-1]-sumb[p[i-1]]+dp[i-1]);//第二项
        sumc+=c[p[i]];//更新sumc
        if(i<=m)
            dp[i]=min(dp[i],a[p[i]]+sumc);//第三项,注意多了c[p[i]]
    }
    printf("%lld\n",dp[m+1]);//输出答案

期望得分

4545 分。结合 测试点 121\sim2 的算法可以获得 5555 分。

测试点 121312\sim13

做法

vali=aij=1ibjval_i=a_i-\displaystyle\sum_{j=1}^ib_j,则前述有关 dpdp 表达式也可写作:

$$dp_i=\min(\displaystyle\sum_{k=1}^{p_{i-1}}[k\in P]c_k+\displaystyle\sum_{k=1}^{p_i-1}b_k+\displaystyle\min_{j=p_{i-1}+1}^{p_i-1}val_j,dp_{i-1}+\displaystyle\sum_{k=p_{i-1}+1}^{p_i-1}b_k,a_{p_i}+\displaystyle\sum_{k=1}^{p_i}[k\in P]c_k) $$

对于第一个式子,使用 分块 事先计算每个整块内的 valival_i 的最小值即可。

正确性证明

上式中,第二、三个式子可以直接转移。

考虑将第一个式子进行变形:

$$\begin{aligned}\displaystyle\min_{j=p_{i-1}+1}^{p_i-1}\{\displaystyle\sum_{k=1}^{p_{i-1}}[k\in P]c_k+a_j+\displaystyle\sum_{k=j+1}^{p_i-1}b_k\} &=\displaystyle\sum_{k=1}^{p_{i-1}}[k\in P]c_k+\displaystyle\min_{j=p_{i-1}+1}^{p_i-1}\{a_j+\displaystyle\sum_{k=1}^{p_i-1}b_k-\displaystyle\sum_{k=1}^jb_k\}\\ &=\displaystyle\sum_{k=1}^{p_{i-1}}[k\in P]c_k+\displaystyle\min_{j=p_{i-1}+1}^{p_i-1}\{a_j-\displaystyle\sum_{k=1}^jb_k+\displaystyle\sum_{k=1}^{p_i-1}b_k\}\\ &=\displaystyle\sum_{k=1}^{p_{i-1}}[k\in P]c_k+\displaystyle\min_{j=p_{i-1}+1}^{p_i-1}\{val_j+\displaystyle\sum_{k=1}^{p_i-1}b_k\}\\ &=\displaystyle\sum_{k=1}^{p_{i-1}}[k\in P]c_k+\displaystyle\sum_{k=1}^{p_i-1}b_k+\displaystyle\min_{j=p_{i-1}+1}^{p_i-1}val_j \end{aligned}$$

可以发现,该式子变成了两个可预处理或动态更新的 定值 与一个 区间最小值 的形式,并且该序列 valval 不会发生改变。因此我们可以直接运用分块思想,处理出每一块的最小值,加速询问的回答。

在恒等变形中每一步都保证正确,因此思路正确。

具体实现

预处理 vali=aisumbival_i=a_i-sumb_i,并对 valval 数组分块:每 O(n)O(\sqrt n) 个元素切成一个块,并预处理第 ii 块中的 valival_i 最小值 minniminn_i。其余预处理与 测试点 8118\sim11 中所述相同。

对于每个询问,加速 dp 转移:对于第一个式子,计算 mini=lrvali\displaystyle\min_{i=l}^rval_i 时,将询问区间划分为中间的 整块 与两端 散块。对于所有整块,直接取对应块中的最小值;否则,暴力扫对应 散块区间,求最小值。求出区间最小值,并计算,更新答案。

其余仍按照 dpdp 表达式转移即可。

最后输出 dpm+1dp_{m+1}

时间复杂度分析

由 测试点 8118\sim11 的分析可知,复杂度瓶颈在 dp。对于每次转移,分块求区间最小值,整块最多 O(n)O(\sqrt n) 个,散块大小在 O(n)O(\sqrt n) 级别,复杂度为 O(n)O(\sqrt n),因此回答每次询问的复杂度为 O(mn)O(m\sqrt n)

总时间复杂度 O((q+m)n)O((q+\sum m)\sqrt n)。根据该解法,可以通过 测试点 1131\sim13

参考核心代码

void InitBlock(){//初始化分块,预处理每个块val[i]最小值
    siz=sqrt(n);
    int num=n/siz+(n%siz!=0);
    for(int i=1;i<=n;i++)
        bel[i]=i/siz+(i%siz!=0);
    for(int i=1;i<=num;i++){
        int bl=siz*(i-1)+1,br=siz*i;
        minn[i]=INF;
        for(int j=bl;j<=br;j++)
            minn[i]=min(minn[i],val[j]);//预处理出最小值
    }
}
long long Min(int l,int r){//暴力求区间最小值
    long long ans=INF;
    for(int i=l;i<=r;i++)
        ans=min(ans,val[i]);
    return ans;
}
long long MinInterval(int l,int r){//求区间最小值
    if(l>r)
        return INF;
    if(bel[l]==bel[r])
        return Min(l,r);//同一块内直接暴力求
    long long ans=INF;
    for(int i=bel[l]+1;i<=bel[r]-1;i++)
        ans=min(ans,minn[i]);//中间整块
    int rtl=bel[l]*siz,ltr=(bel[r]-1)*siz+1;
    return min({Min(l,rtl),ans,Min(ltr,r)});//两端散块取最小值,再与ans取min
}

期望得分

7575 分。(4)(4)

测试点 142014\sim20

做法

dpdp 数组和 valval 数组含义与 测试点 8158\sim15 相同。

在每次计算转移方程的第一项时,使用 ST 表 快速求其中的 minj=pi1+1pi1valj\displaystyle\min_{j=p_{i-1}+1}^{p_i-1}val_j 即可。

正确性证明

dp 转移的正确性已经在 测试点 8118\sim11 中证明。

可以发现 valval 数组具有 静态 的特点,因此可以使用 ST 表加速求 静态区间最小值

故该思路正确。

具体实现

使用 ST 表,预处理 valval 数组中每个 ii 开始,长度为 2j2^j 的区间最小值,记为 STi,jST_{i,j}

在求区间 [l,r][l,r] 的最小值时,令 x=log2(rl+1)x=\lfloor\log_2(r-l+1)\rfloor,只需求出 min(STl,x,STr2x+1,x)\min(ST_{l,x},ST_{r-2^x+1,x}) 即可。

仍按照上述 dpdp 表达式进行转移。最终输出 dpm+1dp_{m+1}

时空复杂度分析

时间复杂度:对于每次 dp 转移,由于使用 ST 表,故可以做到 O(1)O(1)。因此处理所有询问,总复杂度为 O(q+m)O(q+\sum m)。预处理出 ST 表需要 O(nlogn)O(n\log n) 的复杂度。

总时间复杂度 O(nlogn)O(n\log n),可以通过 本题

空间复杂度:ST 表本身需要 O(nlogn)O(n\log n) 的空间复杂度,其余数组空间复杂度为 O(n)O(n)

空间复杂度 O(nlogn)O(n\log n),可以通过 本题

参考核心代码

long long MinInterval(int l,int r){//ST表单次询问求区间最小值
    if(l>r)
        return INF;
    long long ex=log_2[r-l+1];
    return min(ST[l][ex],ST[r-(1<<ex)+1][ex]);
}
...//预处理部分
    for(i=1;i<=n;i++)
        ST[i][0]=val[i];
...
    for(i=1;i<=log_2[n];i++)
        for(j=1;j<=n-(1<<i)+1;j++)
            ST[j][i]=min(ST[j][i-1],ST[j+(1<<(i-1))][i-1]);//ST 表预处理
...
    ...
    dp[i]=min(dp[i],sumb[p[i]-1]+sumc+MinInterval(p[i-1]+1,p[i]-1));//转移该式子时只需调用MinInterval函数即可
    ...//其余的dp转移

期望得分

100100 分。


(1)(1) 实际上,该实现也通过了 测试点 77

(2)(2) 实际上,该实现也通过了 测试点 44

(3)(3) 实际上,该实现也通过了 测试点 12,1213,171\sim2,12\sim13,17

(4)(4) 实际上,该实现也通过了 测试点 142014\sim20