[ACNOI2022]六道⋅枪杆政权

220 篇文章 2 订阅
14 篇文章 0 订阅

题目

题目背景
你知道 I O e r \rm IOer IOer 吗?它是 Intelligence Originator \textrm{Intelligence Originator} Intelligence Originator 的缩写(由于 o r \rm or or 结尾与 O \rm O O 重复,改为 e r \rm er er 较为美观),即 智能起源 。也许有人已经知道 O U Y E \sf OUYE OUYE 是人类智能之祖了;也许有人不知道。无论如何,接下来要讲的是,人类智能诞生之初的故事。

本来这个世界充斥着祥和之气。直到有一天,大卷筒挥杆卷爷 之母)吃下了「卷之果实」,获得了一种非凡的能量,后世称为「卷坷垃」 c h u a k r a \rm chuakra chuakra 。正是凭借着这种力量,大卷筒挥杆 成功地征服了天下。道上行人皆崇卷,学堂处处是卷生。

然而,「卷坷垃」对身体的伤害是这样大,以致于人们很快就变得衰弱不堪,仿佛饿死者的尸体。这种病态的现象被称为 白卷绝。为了挽救这一切,大卷筒挥杆 的两个儿子 卷爷标杆 毅然决然与母亲决裂,打响了一场天变地异的战争!

山峦崩摧。江河断流。日月无光。没人知道这场战争持续了多久。最后,卷爷 用他的 标枪 之力,与 标杆 之力融汇,用一式「六道 ⋅ \large\cdot 枪杆 政权」封印了 大卷筒挥杆,世界回归平静……

题目描述
枪杆 政权,需要「卷坷垃」连成两把枪搭在一起的形状。形式化地,如果用 s i s_i si 表示第 i i i 个「卷坷垃」所在的高度,若共有 n n n 个「卷坷垃」,则 枪杆 政权的使用条件是
∃ k ∈ [ 1 , n ] , s.t.    ∀ i ∈ [ 1 , n ] ,    s i = s k − ∣ k − i ∣ \exist k\in[1,n],\text{s.t.}\;\forall i\in[1,n],\;s_i=s_k-|k-i| k[1,n],s.t.i[1,n],si=skki

假设使用 k k k 个「卷坷垃」将使得封印强度增加 v k v_k vk 。最初有 n n n 个「卷坷垃」,高度分别为 a i a_i ai,每次可以选择若干个相邻「卷坷垃」发动 枪杆 政权(然后这些「卷坷垃」会消失,两边的「卷坷垃」变为相邻的)。

问,最多能够让封印强度达到多少。注意 v v v 可能为负,即使得封印变弱。不要求使用所有「卷坷垃」。

数据范围与约定
n ⩽ 400 n\leqslant 400 n400 ∣ v i ∣ ⩽ 1 0 5 |v_i|\leqslant 10^5 vi105 1 ⩽ a i ⩽ 1 0 9 1\leqslant a_i\leqslant 10^9 1ai109

思路

最初总是考虑取出极长可操作段。最终才发现这玩意儿真没啥用。

不如想想一般做法:每次只能删去相邻元素,可以考虑 区间 d p \tt dp dp 。于是考虑某一次删除 d d d,其删除了第一个元素 l l l,设 d d d 同时删去的最右元素为 k k k 。则 [ l , k ] [l,k] [l,k] 之间,除了 d d d 中删除的,剩下的元素是若干个 独立 的区间。就可以 d p \tt dp dp 算贡献了。

于是,对于每个 l l l,都要记录 g ( k , t , 0 / 1 ) g(k,t,0/1) g(k,t,0/1) 表示删去 [ l , k ] [l,k] [l,k] 之间若干段区间,使得剩下一个长度为 t t t 的可删除序列,它现在在 “上坡” 还是 “下坡”。这样是 O ( n 4 ) \mathcal O(n^4) O(n4) 的,不具有决策点单调性,不会优化。

最重要的是,找到无用信息。有趣的是,等差数列的项数可以直接算出,而不需额外记录。也就是说,如果找到最高点 a k a_k ak,又知道端点 a l , a r a_l,a_r al,ar,那么项数就是 2 a k − a l − a r + 1 2a_k-a_l-a_r+1 2akalar+1,可以直接算出。于是我们考虑枚举最高点,然后去掉个数限制。

不幸的是,我们好像还是要枚举与 l l l 同时被删除的最右元素? n o , n o , n o \rm no,no,no no,no,no充分利用已有 d p \tt dp dp 。它可以直接从 f ( l , k ) + f ( k + 1 , r ) f(l,k)+f(k{\rm+}1,r) f(l,k)+f(k+1,r) 转移过来!反正就是把 [ l , k ] [l,k] [l,k] 删完嘛!

所以被删除的最右元素就是区间右端点。复杂度 O ( n 3 ) \mathcal O(n^3) O(n3) 。最后做一个一维 d p \tt dp dp 去掉不删除的元素即可。

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
typedef long long llong;
inline int readint(){
	int a = 0, c = getchar(), f = 1;
	for(; !isdigit(c); c=getchar())
		if(c == '-') f = -f;
	for(; isdigit(c); c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}
inline void getMax(int &a, const int &b){
	if(a < b) a = b;
}

const int MAXN = 405;
int f[MAXN][MAXN], up[MAXN][MAXN], dn[MAXN][MAXN];
int a[MAXN], v[MAXN], ans[MAXN];

const int INF = 0x2fffffff;
int main(){
	int n = readint();
	rep(i,1,n) v[i] = readint();
	rep(i,1,n) a[i] = readint();
	drep(l,n,1) rep(r,l,n){
		f[l][r] = up[l][r] = dn[l][r] = -INF;
		up[l][l] = dn[l][l] = 0; // init state
		for(int i=l; i!=r; ++i){
			getMax(f[l][r],f[l][i]+f[i+1][r]);
			if(a[i]+1 == a[r]) getMax(up[l][r],up[l][i]+f[i+1][r-1]);
			if(a[i]-1 == a[r]) getMax(dn[l][r],dn[l][i]+f[i+1][r-1]);
			if(a[i] >= a[l] && a[i] >= a[r]) getMax(f[l][r],
				up[l][i]+dn[i][r]+v[(a[i]<<1)-a[l]-a[r]+1]);
		}
		if(a[l] >= a[r]) getMax(f[l][r],dn[l][r]+v[a[l]-a[r]+1]);
		if(a[r] >= a[l]) getMax(f[l][r],up[l][r]+v[a[r]-a[l]+1]);
	}
	rep(i,1,n){
		ans[i] = ans[i-1]; // not to del this
		rep(j,1,i) getMax(ans[i],ans[j-1]+f[j][i]);
	}
	printf("%d\n",ans[n]);
	return 0;
}

后记

有一点像这个题,拼接两个 d p \tt dp dp 值。这两题最相似的地方在于,都是我不会做的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值