简单区间dp
观察合法序列定义等价于以下条件
对于一个序列,有且仅有一个
k
k
k使得
a
i
=
a
i
−
1
+
1
,
i
<
=
k
a_i=a_{i-1}+1,i<=k
ai=ai−1+1,i<=k且
a
i
=
a
i
−
1
−
1
,
i
>
k
a_i=a_{i-1}-1,i>k
ai=ai−1−1,i>k
考虑算出删除某段区间的最大价值
f
i
,
j
f_{i,j}
fi,j
建出序列自动机即可转移
注意:直接转移难以通过,考虑如下优化
V
i
=
m
a
x
(
V
i
,
V
j
+
V
i
−
j
)
V_i=max(V_i,V_j+V_{i-j})
Vi=max(Vi,Vj+Vi−j)
删除区间越长价值越大
其他优化此处略
合并答案即可
#include <bits/stdc++.h>
using namespace std;
struct Ele
{
int a, Id, Num;
}E[155];
int Num[155];
bool Cmp(Ele a, Ele b)
{
return a.a < b.a;
}
int Trans[155][305];
int f[155][155];
int V[155];
int R;
int Res;
void Dfs(int x, bool Flag, int Len, int Sum)
{
if (x > R)
return;
Res = max(Res, Sum + V[Len] + f[x + 1][R] );
if (Res >= Sum + V[Len + R - x] )
return;
if (x == R)
return;
if (!Flag)
{
for (int i = Trans[x][Num[x] + 1] ; i ; i = Trans[i + 1][Num[x] + 1] )
Dfs(i, false, Len + 1, Sum + f[x + 1][i - 1] );
}
for (int i = Trans[x][Num[x] - 1] ; i ; i = Trans[i + 1][Num[x] - 1] )
Dfs(i, true, Len + 1, Sum + f[x + 1][i - 1] );
return;
}
int Calc(int l, int r)
{
R = r, Res = -2e9;
Dfs(l, false, 1, 0);
return Res;
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 1 ; i <= n ; ++ i)
scanf("%d", &V[i] );
for (int i = 1 ; i <= n ; ++ i)
for (int j = 1 ; j << 1 <= i ; ++ j)
V[i] = max(V[i], V[i - j] + V[j] );
for (int i = 1 ; i <= n ; ++ i)
scanf("%d", &E[i].a), E[i].Id = i;
sort(E + 1, E + n + 1, Cmp);
int k = 1;
E[1].Num = 1;
for (int i = 2 ; i <= n ; ++ i)
if (E[i].a == E[i - 1].a)
E[i].Num = k;
else
if (E[i].a == E[i - 1].a + 1)
E[i].Num = ++ k;
else
E[i].Num = (k += 2);
for (int i = 1 ; i <= n ; ++ i)
Num[E[i].Id] = E[i].Num;
for (int i = n ; i ; Trans[i][Num[i] ] = i, -- i)
for (int j = 1 ; j <= k ; ++ j)
Trans[i][j] = Trans[i + 1][j];
for (int i = 1 ; i <= n ; ++ i)
f[i][i] = V[1];
for (int Len = 2 ; Len <= n ; ++ Len)
for (int i = 1 ; i + Len - 1 <= n ; ++ i)
{
int j = i + Len - 1;
f[i][j] = Calc(i, j);
}
for (int Len = 2 ; Len <= n ; ++ Len)
for (int i = 1 ; i + Len - 1 <= n ; ++ i)
{
int j = i + Len - 1;
for (int k = i ; k < j ; ++ k)
f[i][j] = max(f[i][j], max(f[i][k], 0) + max(f[k + 1][j], 0) );
}
printf("%d\n", f[1][n] );
return 0;
}