zoukankan      html  css  js  c++  java
  • HDU-6549 String (前后缀优化dp)

    题目链接:HDU-6549 String

    题意

    wls 有一个长度为 $n$ 的字符串,每次他可以将一个长度不大于 $L$ 的子串修改成同一种字母,问至少修改多少次可以使字符串最多含有 $k$ 段。连续的只含同一种字母的子串被称为一段,比如说 aaabbccaaa 共含有 4 段。

    ($1leq n, L leq 10^5, 1leq k leq 10$)


    思路

    定义 dp[i][j][p],表示第 i 位为 j+'a' 时 [0, i] 至多 p 段的最小修改次数。

    如果 str[i] == j+'a',第 i 位不用修改,那么dp值直接从 i-1 转移过来:
    $$
    dp[i][j][p] = min(dp[i-1][j][p], dp[i-1][c][p-1]),(cin [0,25],c ot= j)
    $$

    否则第 i 位必须要修改一次,因为最后要求的是最少修改多少次使得字符串最多含有 k 段,根据贪心策略,尽量修改更多,使前面更多位与第 i 位为同一段,那么dp值从 max(i-L, 0) 转移过来:
    $$
    dp[i][j][p] = min(dp[q][j][p], dp[q][c][p-1])+1,(q = max(0, i-L),cin [0,25], c ot= j)
    $$

    这样时间复杂度是 $O(26^2nk)$,可以通过前后缀优化,优化掉 $c$ 的遍历。定义 $pre[i][j][p]$ 表示 $dp[i][0sim j][p]$ 的最小值,$suf[i][j][p]$ 表示 $dp[i][jsim 25][p]$ 的最小值,则

    当 str[i] == j+'a' 时:
    $$
    dp[i][j][p] = min(dp[i-1][j][p], pre[i-1][j-1][p-1], suf[i-1][j+1][p-1])
    $$
    当 str[i] != j+'a' 时:
    $$
    dp[i][j][p] = min(dp[q][j][p], pre[q][j-1][p-1], suf[q][j+1][p-1])+1,(q=max(0,i-L))
    $$

    这样时间复杂度是 $O(26nk)$。

    边界的转移要注意一下。


    代码实现 

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using std::max;
    using std::min;
    const int INF = 0x3f3f3f3f;
    const int N = 100010;
    // dp[i][j][p]表示第i位为j+'a'时[0,i]至多q段的最小修改次数
    // pre[i][j][p]表示dp[i][0~j][p]的最小值
    // suf[i][j][p]表示dp[i][j~25][p]的最小值
    int dp[N][27][11], pre[N][27][11], suf[N][27][11];
    char str[N];
    void init() {
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < 26; j++) {
                dp[i][j][0] = INF;
                pre[i][j][0] = INF;
                suf[i][j][0] = INF;
            }
        }
        for (int i = 0; i < 26; i++) {
            if (str[0] == i + 'a') dp[0][i][1] = 0;
            else dp[0][i][1] = 1;
            if (i) pre[0][i][1] = min(pre[0][i-1][1], dp[0][i][1]);
            else pre[0][i][1] = dp[0][i][1];
        }
        suf[0][25][1] = dp[0][25][1];
        for (int i = 24; i >= 0; i--) suf[0][i][1] = min(suf[0][i+1][1], dp[0][i][1]);
    }
    
    int main() {
        int n, l, k;
        while (~scanf("%d %d %d %s", &n, &l, &k, str)) {
            init();
            for (int i = 1; i < n; i++) {
                for (int j = 0; j < 26; j++) {
                    for (int p = 1; p <= k; p++) {
                        if (str[i] == 'a' + j) {
                            dp[i][j][p] = min(dp[i-1][j][p], min((j ? pre[i-1][j-1][p-1] : INF), (j == 25 ? INF : suf[i-1][j+1][p-1])));
                        }
                        else {
                            int q = max(0, i - l);
                            dp[i][j][p] = min(dp[q][j][p], min((j ? pre[q][j-1][p-1] : INF), (j == 25 ? INF : suf[q][j+1][p-1]))) + 1;
                        }
                        if (j) pre[i][j][p] = min(pre[i][j-1][p], dp[i][j][p]);
                        else pre[i][j][p] = dp[i][j][p];
                    }
                }
                for (int j = 25; j >= 0; j--) {
                    for (int p = 1; p <= k; p++) {
                        if (j < 25) suf[i][j][p] = min(suf[i][j+1][p], dp[i][j][p]);
                        else suf[i][j][p] = dp[i][j][p];
                    }
                }
            }
            printf("%d
    ", pre[n-1][25][k]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Centos 安装git
    mybatis 整合redis作为二级缓存
    jedis 连接池工具类
    IE8下使用asp.net core mvc+jquery ajaxSubmit问题
    .net core mvc部署到IIS导出Word 提示80070005拒绝访问
    IdentityServer4在Asp.Net Core中的应用(三)
    理解OpenID和OAuth的区别
    IdentityServer4在Asp.Net Core中的应用(二)
    使用Bind读取配置到C#的实例
    IdentityServer4在Asp.Net Core中的应用(一)
  • 原文地址:https://www.cnblogs.com/kangkang-/p/11642022.html
Copyright © 2011-2022 走看看