zoukankan      html  css  js  c++  java
  • 「CF1366G」 Construct the String「DP」

    CF1366G Construct the String

    题解

    我们把题目中的函数 (f(s)) 叫做「转换」。

    用一个很朴素的dp:(f_{i,j}) 表示 (s)(i) 位最少删除几个位置使得转换后等于 (t)(j) 个位置。

    边界就是 (f_{0,0}=0),转移分几种情况:

    • 直接删去 (i + 1)(f_{i,j} ightarrow f_{i+1},j)
    • (s_{i+1}=t_{j+1}),往后匹配一位:(f_{i,j} ightarrow f_{i+1,j+1})
    • (s_{i+1}) 为点:(f_{i,j} ightarrow f_{i+1,j-1})

    这样够了吗?不够。还漏了一种情况:加的字符无法与 (t) 匹配,但最后都用点删去了,还是合法的转移。

    预处理一个 (a_i) 表示串 (s)(i) 往后长度最短、满足转换后为空串的串长度。再加个转移 (f_{i,j} ightarrow f_{i + a_{i+1},j})

    考虑正确性,转移显然都合法,现证明最优解能取到。最优方案中最终形成 (t) 的“骨架”拎起来,那骨架的每段间隙中没有删除的位置形成的一定是空串。

    给一个串 (S),选一个子序列转换后是空串,最优选取方案一定是:把字母做 (,点做),遇到(就选,遇到)时候有左括号配对就选,最后再把多余的(退回去。你会发现选出的是一些子段,每一段都是合法的括号序列。

    而我们的 (a_i) 就表示 (i) 开始的最短的括号序列且不能分割成两半。而拼接的情况如(())()可以通过(())()两次转移实现。

    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    template<typename T>
    void chkmin(T &x, const T &y) { if(x > y) x = y; }
    const int N = 1e4 + 5, INF = 2 * N;
    char s[N], t[N];
    short dp[N][N], a[N];
    int n, m;
    int main() {
       scanf("%s%s", s + 1, t + 1);
       n = strlen(s + 1); m = strlen(t + 1);
       for(int i = 1; i <= n; i ++) {
          int y = 0;
          for(int j = i; j <= n; j ++) {
             if(s[j] == '.') {
                if(!y) break ;
                else {
                   y --; a[i] ++;
                   if(!y) break ;
                }
             } else {
                a[i] ++; y ++;
             }
          }
          if(y) a[i] = 0;
       }
       for(int i = 0; i <= n; i ++) fill(dp[i], dp[i] + m + 1, INF);
       dp[0][0] = 0;
       for(int i = 0; i <= n; i ++) {
          for(int j = 0; j <= m; j ++) if(dp[i][j] < INF) {
             if(i < n) chkmin(dp[i + 1][j], short(dp[i][j] + 1));
             if(i < n && j < m && s[i + 1] == t[j + 1]) chkmin(dp[i + 1][j + 1], dp[i][j]);
             if(j && i < n && s[i + 1] == '.') chkmin(dp[i + 1][j - 1], dp[i][j]);
             if(a[i + 1]) chkmin(dp[i + a[i + 1]][j], dp[i][j]);
          }
       }
       printf("%d
    ", (int) dp[n][m]);
       return 0;
    }
    
  • 相关阅读:
    编译错误总结。
    9.7
    9.5
    9.6
    9.4
    9.3
    FutureTask取结果超时代码小测试
    java concurrent包常用类小结
    java Nio零散知识点整理
    java进阶教程unit_2java常用类(2)
  • 原文地址:https://www.cnblogs.com/hongzy/p/13113460.html
Copyright © 2011-2022 走看看