洛谷 CF1107E Vasya and Binary String(区间dp)

传送门


解题思路

看出是区间dp,但是就是不会设计状态,不会写状态转移方程/kk/kk

设dp[i][j][k]表示区间i到j加上左面连续k个a[i]的答案。
最后答案即为dp[1][n][0]。

状态转移分为两种情况:

  • 让前k个和第i位连起来处理:dp[i+1][j][0]+w[k+1]
  • 枚举断点p,让i+1到p-1先单独处理完,相当于把i和p连起来:dp[i+1][p-1][0]+dp[p][j][k+1]

取个max即可。

枚举i、j、k、p,所以最后复杂度为 \(O(n^4)\)。

AC代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
template<class T>inline void read(T &x)
{
    x=0;register char c=getchar();register bool f=0;
    while(!isdigit(c))f^=c=='-',c=getchar();
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    if(f)x=-x;
}
template<class T>inline void print(T x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)print(x/10);
    putchar('0'+x%10);
}
const int maxn=105;
int n;
long long a[maxn],w[maxn],dp[maxn][maxn][maxn];
string s;
int main(){
	ios::sync_with_stdio(false);
	cin>>n>>s;
	for(int i=1;i<=n;i++) cin>>w[i],a[i]=s[i-1];
	for(int len=1;len<=n;len++){
		for(int i=1;i<=n;i++){
			int j=i+len-1;
			for(int k=0;k<=n;k++){
				dp[i][j][k]=max(dp[i][j][k],dp[i+1][j][0]+w[k+1]);
				for(int p=i+1;p<=j;p++){
					if(a[i]==a[p]) dp[i][j][k]=max(dp[i][j][k],dp[i+1][p-1][0]+dp[p][j][k+1]);
				}
			}
		}
	}
	cout<<dp[1][n][0];
    return 0;
}
上一篇:打印出Ibatis最终的SQL语句


下一篇:mysql日志