区间DP复习
区间DP的套路性还是很强的。一般就是转移方程都是f[l,r]或者有时候区间状态不好表示的时候需要用状压也就是f[l,r,sates]。(后者应该属于比较难的那种了)
区间DP一般我们的步骤就是
1,枚举区间长度,
2,枚举左端点,同时枚举右端点
3,枚举区间内的中间节点(会造成影响的last点)
4,根据状态转移方程式来进行转移。有时候边状态转移的时候还需要记录信息。
以加分二叉树为例,我们记录一个二叉树的区间最大值的同时还需要记录他的根。
#include <bits/stdc++.h>
using namespace std;
const int N=100+7;
int a[N],f[N][N];
int rt[N][N];
void print(int l,int r)
{
if(l>r) return ;
printf("%d ",rt[l][r]);
int root=rt[l][r];
print(l,root-1);
print(root+1,r);
}
int main()
{
int n; cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++){
for(int j=1;j+i-1<=n;j++){
int l=j,r=j+i-1;
for(int k=l;k<=r;k++){
int left,right;
if(i==1){
rt[l][r]=l;
f[l][r]=a[l];
}
else {
if (l == k) {
left = 1;
} else {
left = f[l][k-1];
}
if (r == k) {
right = 1;
} else {
right = f[k+1][r];
}
int score = left*right + a[k];
if(score>f[l][r]){
f[l][r]=score;
rt[l][r]=k;
}
}
}
}
}
cout<<f[1][n]<<endl;
print(1,n);
}