LuoguP1389

简单区间dp
观察合法序列定义等价于以下条件
对于一个序列,有且仅有一个 k k k使得
a i = a i − 1 + 1 , i < = k a_i=a_{i-1}+1,i<=k ai=ai1+1,i<=k a i = a i − 1 − 1 , i > k a_i=a_{i-1}-1,i>k ai=ai11,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+Vij)
删除区间越长价值越大
其他优化此处略
合并答案即可

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值