“unexpected, right?”大概可以翻译成“没想到吧!”
题意:给两个序列$w_{1\cdots n}$和$v_{1\cdots n}$,你可以多次删除$w$的子串$w_{l\cdots r}$并获得$v_{r-l+1}$分,被删除的$w_{l\cdots r}$要满足:对$\forall i\in[l,r-1]$有$|w_i-w_{i+1}|=1$且对$\forall i\in[l+1,r-1]$有$2w_i-w_{i-1}-w_{i+1}\geq0$,问最多获得多少分
说白了就是只能删(连续上升的/连续下降的/先连续上升后连续下降的)
设$f_{i,j}$表示删完$w_{i\cdots j}$的最大分数,$g_{i,j,0}$表示把$w_{i\cdots j}$删至连续上升的最大分数,$g_{i,j,1}$表示把$w_{i\cdots j}$删至连续下降的最大分数
$g_{i,j,0}=\max\left\{[w_{j-1}+1=w_j]g_{i,j-1,0},\mathop\max\limits_{k=i}^{j-2}\left\{[w_k+1=w_j](g_{i,k,0}+f_{k+1,j-1})\right\}\right\}$(可以直接在$w_{i\cdots j-1}$后加上$w_j$,也可以从中间选一个位置$k$,把$w_{k+1\cdots j-1}$删完,再接上$w_j$)
$g_{i,j,1}=\max\left\{[w_{j-1}-1=w_j]g_{i,j-1,1},\mathop\max\limits_{k=i}^{j-2}\left\{[w_k-1=w_j](g_{i,k,1}+f_{k+1,j-1})\right\}\right\}$(同理)
$f_{i,j}=\max\left\{\begin{matrix}[1\leq w_j-w_i+1\leq n](g_{i,j,0}+v_{w_j-w_i+1})\\ [1\leq w_i-w_j+1\leq n](g_{i,j,1}+v_{w_i-w_j+1})\\\mathop\max\limits_{k=i}^{j-1}\left\{f_{i,k}+f_{k+1,j}\right\}\\\mathop\max\limits_{k=i+1}^{j-1}\left\{[1\leq2w_k-w_i-w_j+1\leq n]g_{i,k,0}+g_{k,j,1}+v_{2w_k-w_i-w_j+1}\right\}\end{matrix}\right\}$(可以先删成连续上升或连续下降再直接删除,也可以先删$w_{i\cdots k}$再删$w_{k+1\cdots j}$,还可以先删成上升下降再整段删除)
最后再DP求出最大的$[i,j]$互不相交的$f_{i,j}$之和即可
#include<stdio.h>
const int inf=100000000;
int v[410],w[410],f[410][410],g[410][410][2],ans[410];
void max(int&a,int b){
if(a<b)a=b;
}
int main(){
int n,i,j,k;
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",v+i);
for(i=1;i<=n;i++)scanf("%d",w+i);
for(i=1;i<=n;i++){
for(j=1;j<=n;j++)f[i][j]=g[i][j][0]=g[i][j][1]=-inf;
}
for(i=n;i>0;i--){
f[i][i]=v[1];
g[i][i][0]=g[i][i][1]=0;
for(j=i+1;j<=n;j++){
for(k=i;k<j-1;k++){
if(w[k]+1==w[j])max(g[i][j][0],g[i][k][0]+f[k+1][j-1]);
}
if(w[j-1]+1==w[j])max(g[i][j][0],g[i][j-1][0]);
}
for(j=i+1;j<=n;j++){
for(k=i;k<j-1;k++){
if(w[k]-1==w[j])max(g[i][j][1],g[i][k][1]+f[k+1][j-1]);
}
if(w[j-1]-1==w[j])max(g[i][j][1],g[i][j-1][1]);
}
for(j=i;j<=n;j++){
if(w[j]-w[i]+1>0&&w[j]-w[i]+1<=n)max(f[i][j],g[i][j][0]+v[w[j]-w[i]+1]);
if(w[i]-w[j]+1>0&&w[i]-w[j]+1<=n)max(f[i][j],g[i][j][1]+v[w[i]-w[j]+1]);
for(k=i;k<j;k++)max(f[i][j],f[i][k]+f[k+1][j]);
for(k=i+1;k<j;k++){
if(2*w[k]-w[i]-w[j]+1>0&&2*w[k]-w[i]-w[j]+1<=n)max(f[i][j],g[i][k][0]+g[k][j][1]+v[2*w[k]-w[i]-w[j]+1]);
}
}
}
for(i=1;i<=n;i++){
ans[i]=ans[i-1];
for(j=0;j<i;j++)max(ans[i],ans[j]+f[j+1][i]);
}
printf("%d",ans[n]);
}