1 条题解

  • 0
    @ 2021-8-20 11:04:07

    这题要分成两个问题

    • 可以删出来哪些字符串。
    • 哪一种字符串最小。

    每次删除的字符串一定从某个点开始是连续的一段。并且如果我们能删除s[l...r]s[l . . . r] ,那么就可以删除s[l..r1]s[l..r-1]

    先来看问题1

    dp[c][l][r]dp[c][l][r] 表示之前有个c的情况下,是否能删

    dp[c][l][r]=dp[c][l][m]&&dp[c][m+1][r]dp[c][l][r]=dp[c][l][m] \&\& dp[c][m+1][r]

    O(n3k)O\left(n^{3} \cdot k\right)

    可以优化一下

    dp[c][l]=rdp[c][l]=r

    dp[c][l]=max(dp[c][l],dp[c][r])dp[c][l]=max(dp[c][l],dp[c][r]) (rdp[c][l]&A[c][s[r]])(r\leq dp[c][l] \& A[c][s[r]])

    O(n2k)O\left(n^{2} \cdot k\right)

    当然dp是过不去的,得用其他的方法。

    用一个栈,倒序枚举,如果ii号点 A[s[i]][s[stack.top()]]=1A[s[i]][s[stack.top()]]=1 ,那么stack.pop()stack.pop().

    否则dp[i]=stack.top()1dp[i]=stack.top()-1

    让我们来证明这个算法。假设对于某些dp[i]dp[i] 是错的。考虑这些ii中最右边的一个。我们决定该段在yy处结束(y=st.top()1y=st.top() - 1),A[s[i]][s[y+1]]=0A[s[i]][s[y + 1]] = 0,但实际上该段应该在rr处结束(y<ry < r)。考虑一下把删除关系建出来的树。s[y+1]s[y+1]不能是s[i]s[i]的直系子女。让我们从s[y+1]s[y+1]往上走,直到到达s[i]s[i]的孩子,让它成为s[x]s[x]。根据假设,对于s[x]s[x],我们可以找到yy, yy 一定会被s[x]s[x] 删掉。所以当我们考虑s[i]s[i]时,yy 不可能出现在栈中。矛盾。

    考虑问题2。

    ans[i]ans[i] 表示 s[i..n]s[i..n] 中最小的字典序字符串。那么

    ans[i]=min(ans[i],s[i]+ans[j])ans[i]=min(ans[i],s[i]+ans[j])

    O(n3)O\left(n^{3} \right)

    如果记next而不是字符串。

    $ans[i]=s[i]+s[\operatorname{next}[i]]+s[\operatorname{next}[\operatorname{next}[i]]+\ldots$

    利用hash+倍增跳比较字符串,可以优化到O(n2logn)O\left(n^{2} logn \right)

    image-20210820143443487

    如果我们建树去做。

    $$\huge ans_i=s_i+\min^{dp'[s[i]][i+1]}_{j=i+1} ans_j $$

    单次询问O(log2(n))O(\log ^2 (n)) ,总时间复杂度O(nlog2(n))O(n log^2(n))

    实现提示:倒序枚举,用倍增记录区间最小字符串ans[j]ans[j] ,每次求出ans[i]ans[i] ,更新倍增数组。用hash和倍增判字典序大小。

    最后做法

    让我们结合第一和第二部分的算法。当我们考虑s[i]s[i],并从栈中删除st.top()st.top()时,使ans[i]=min(ans[i],s[i]+ans[st.top()])ans[i] = \min(ans[i], s[i] + ans[st.top()])。这样的算法将进行O(n)O(n)次比较,比较需要O(log(n))O(log(n))。总时限O(nlog(n))O (nlog(n))

    • 1

    信息

    ID
    3
    时间
    1000ms
    内存
    1024MiB
    难度
    9
    标签
    递交数
    97
    已通过
    9
    上传者