zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 59 (Rated for Div. 2) E 区间dp + 状态定义 + dp预处理(分步dp)

    https://codeforces.com/contest/1107/problem/E

    题意

    给出01字符串s(n<=100),相邻且相同的字符可以同时消去,一次性消去i个字符的分数是(a[i]),问消去s最多能得到多少分数

    题解

    • 实质是安排消去次序使得分数最大,第一步采取的行动是递归边界
    • 因为只有01串,所以s被分成了一段一段,考虑段处理
    • 预处理出一次性消去i个字符的最大分数(f[i])
    • 定义(dp[l][r][cnt])为消去第l到第r段加上cnt个字符和第l段相同得到的最大分数
    • 每个区间只考虑第l段消去的情况(立刻消去or和后面的一起消去)
    ans=dfs(l+1,r,0)+f[cnt+b[l]];  //立刻消去第l段
    for(int i=l+2;i<=r;i+=2){
        ans=max(ans,dfs(l+1,i-1,0)+dfs(i,r,b[l]+cnt)); //枚举第二段的分割点,dfs(第二段)+dfs(第l段+第三段)
    }
    

    代码

    #include<bits/stdc++.h>
    #define ll long long 
    #define MAXN 105
    using namespace std;
    ll f[MAXN],dp[MAXN][MAXN][MAXN],a[MAXN];
    vector<int>b;
    string s;
    int n,cnt=0;
    ll dfs(int l,int r,int cnt){
    	if(l>r)return f[cnt];
    	ll &ans=dp[l][r][cnt];
    	if(ans!=-1)return ans;
    	ans=dfs(l+1,r,0)+f[cnt+b[l]];
    	for(int i=l+2;i<=r;i+=2)
    		ans=max(ans,dfs(l+1,i-1,0)+dfs(i,r,b[l]+cnt));
    	return ans;
    }
    int main(){
    	cin>>n>>s;
    	for(int i=1;i<=n;i++)cin>>a[i];
    	f[1]=a[1];
    	for(int i=2;i<=n;i++){
    		f[i]=a[i];
    		for(int j=1;j<i;j++)
    			f[i]=max(f[i],f[j]+f[i-j]);
    	}
    	memset(dp,-1,sizeof(dp));
    	for(int i=0;i<n;i++){
    		if(i==0||s[i]==s[i-1])cnt++;
    		else{
    			b.push_back(cnt);
    			cnt=1;
    		}
    	}
    	b.push_back(cnt);
    	cout<<dfs(0,b.size()-1,0);
    }
    
  • 相关阅读:
    POJ 1995
    POJ 3233
    HDU 2815
    POJ 2417
    POJ 3243
    HDU 3579 线性同余方程组
    HDU 1573
    POJ 2115
    POJ 2891
    HDU 2035 不忍直视的水
  • 原文地址:https://www.cnblogs.com/VIrtu0s0/p/10808744.html
Copyright © 2011-2022 走看看