洛谷 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;
}