zoukankan      html  css  js  c++  java
  • CF1107E Vasya and Binary String

    CF1107E Vasya and Binary String

    Codeforces, Educational Codeforces Round 59 (Rated for Div. 2), CF1107E Vasya and Binary String

    题目大意

    题目链接

    给定一个长度为 (n) 的 01 串 (s),和一个长度为 (n) 的正整数序列 (a)

    你需要进行若干次操作,直到字符串 (s) 为空。每步操作中,可以选择当前串 (s) 里的一段相同字符组成的连续子串,并将其删掉。然后它两边的字符会自动拼接起来。设当前删除的子串长为 (x),那么可以获得 (a_x) 的收益。

    求所有操作完成后,能获得的收益之和的最大值。

    数据范围:(1leq nleq 100)(1leq a_ileq 10^9)

    本题题解

    考虑区间 DP。容易想到的一个状态设计是:( ext{dp}(i,j,k,0/1)),表示只考虑 ([i,j]) 这段区间,还剩下 (k)(0)(1) 没有删除时,能得到的最大收益(不包括这 (k)(0/1) 的收益)。转移需要枚举 (i,j) 中间的断点,再枚举左边剩多少个 (0/1) 没有删掉(左边的知道了,用 (k) 减左边的就是右边的)。特别地,(k = 0) 时可以把两边的、剩余的部分一起消掉,并产生一个收益。时间复杂度 (mathcal{O}(n^5)),无法通过本题。另外,如果把状态简单定义为 ( ext{dp}(i,j)),也能得到一个 (mathcal{O}(n^5)) 做法,这里不细说了。

    我们需要更巧妙的状态设计。

    强行钦定区间的最后一位((j))是还没有被删掉的,或者说是和非当前区间里的数一起删掉的。可以理解为是上一种状态里的 "(k)" 个位置中的一员。

    定义新状态 ( ext{dp}_2(i,j,x)) 表示只考虑 ([i,j]) 这段区间,(j) 后面有 (x) 个数是(要在之后的过程里)和它一起被删掉的。当然,既然只考虑了区间 ([i,j]),那我们也不知道 (j) 后面的串长什么样。所以这 (x) 个数是我们想象出来的,可能根本不存在这些数,但这不重要,我们只要保证能从符合实际的状态转移到答案即可。答案就是 ( ext{dp}(1,n,0))

    转移有两种:

    • 把一段数删掉。这段是就是指 (j) 和它后面的数。于是有转移:( ext{dp}_2(i,j,x)leftarrow ext{dp}_2(i,j,0) + a_{x + 1})
    • 合并两段区间。枚举断点 (pin[i,j)),则:( ext{dp}_2(i,j,x)leftarrow ext{dp}_2(i,p,x + 1) + ext{dp}_2(p + 1, j - 1, 0))。这相当于把 (p)(j)、以及 (j) 后面的 (x) 个数,一起删掉,所以执行这种转移的前提是 (s_{p} = s_{j})。并且,这次删除的收益已经算在 ( ext{dp}_2(i,j,x)) 里了,所以这里不需要加上。

    感性理解:在第一种转移里,我们算上想象中的 (x) 的收益,相当于是开出了一张空头支票。而第二种转移,发现 (x) 减小了 (1),这代表这我们的承诺在一步步兑现。具体来说,就是最后的那一位 (j),从空头支票里走到了现实中。

    于是,这个复杂的操作过程,就被转化为了简单的“开支票,再不断兑现”的过程。并且同一时间只需要处理一张支票,这是因为任意两个操作区间,要么相互并列,要么完全包含,不可能出现相交。([p + 1, j - 1]) 其实就是这种“完全包含”的情况,它是一个完全自闭的区间(自我封闭,也就是已经完结了)。特别地,这个区间的长度可能为 (0),即 (p + 1 = j),此时我们认为 ( ext{dp}_2(p + 1, j - 1, 0) = 0)

    转移的复杂度主要来自于枚举 (p),是 (mathcal{O}(n)) 的。总时间复杂度 (mathcal{O}(n^4))

    参考代码

    // problem: CF1107E
    #include <bits/stdc++.h>
    using namespace std;
    
    #define pb push_back
    #define mk make_pair
    #define lob lower_bound
    #define upb upper_bound
    #define fi first
    #define se second
    #define SZ(x) ((int)(x).size())
    
    typedef unsigned int uint;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    
    template<typename T> inline void ckmax(T& x, T y) { x = (y > x ? y : x); }
    template<typename T> inline void ckmin(T& x, T y) { x = (y < x ? y : x); }
    
    const int MAXN = 100;
    const ll LL_INF = 1e15;
    
    int n, a[MAXN + 5];
    char s[MAXN + 5];
    
    ll dp[MAXN + 5][MAXN + 5][MAXN + 5];
    
    int main() {
    	cin >> n;
    	cin >> (s + 1);
    	for (int i = 1; i <= n; ++i) {
    		cin >> a[i];
    	}
    	
    	for (int i = 1; i <= n; ++i) {
    		for (int j = i; j <= n; ++j) {
    			for (int k = 0; k <= n; ++k) {
    				dp[i][j][k] = -LL_INF;
    			}
    		}
    		for (int k = 0; k <= n - i; ++k) {
    			dp[i][i][k] = a[k + 1];
    		}
    	}
    	
    	for (int len = 2; len <= n; ++len) {
    		for (int i = 1; i + len - 1 <= n; ++i) {
    			int j = i + len - 1;
    			for (int k = 0; k <= n - j; ++k) {
    				ckmax(dp[i][j][k], dp[i][j - 1][0] + a[k + 1]);
    			}
    			
    			for (int k = 0; k <= n - j; ++k) {
    				for (int l = i; l <= j - 1; ++l) if (s[l] == s[j]) {
    					ckmax(dp[i][j][k], dp[i][l][k + 1] + dp[l + 1][j - 1][0]);
    				}
    			}
    		}
    	}
    	cout << dp[1][n][0] << endl;
    	
    	return 0;
    }
    
  • 相关阅读:
    DataPager 分页样式(css)
    Mysql日志详解
    Oracle 优化器
    [oracle]对象统计数据
    [oracle] analyze 和dbms_stats 的区别
    增加SAP HEAP大小
    Problems with SYSDBA/SYSOPER/INTERNAL connect
    Physical Standby Switchover_status Showing Not Allowed
    REHL8 oracle 19C RAC安装中的坑
    REHL8 oracle 19C RAC安装四(数据库创建)
  • 原文地址:https://www.cnblogs.com/dysyn1314/p/14194683.html
Copyright © 2011-2022 走看看