CF1334F Strange Function 题解

传送门

定义一个函数 f,输入一个数组 a,输出一个数组 ba 的子序列:b1=a1,设 bia 中的位置为 posi,则 biaposi1+1an 中第一个严格大于 bi1 的数。n5×105|pi|109,1ai,bin,bi1<bi

给定长度 n 的数组 a 和数组 p,以及长度 mn 的严格递增的数组 b。删除 ai 需要 pi 的代价,问删除一些数使 aaf(a)=b 的最小代价是多少。


转化问题,变成保留一些数最大代价是多少。

注意到 f 的定义是严格递增,所以余下的数必然两两不同,显然用 map 可以 O(nlogn) 预处理出 aib 中哪个位置出现过。

一个简单的思路是 fi 表示考虑 a 的前 i 个数,必须保留 ai(如果 aibfi=),能保留的数的最大价值之和。
ai=bj

写出转移方程:fi=max0ki1,ak=bj1(fk+t=k+1i1[atak][pt>0]pt+pi)

直接硬来是 O(n3) 的,考虑优化。优化 DP 的一个重要思路是动态维护每个决策点的值。

gk=fk+t=k+1i1[atak][pt>0]pt+pi,尝试随着在 i 增大的过程中维护 gkk=0i1)。但就算成功维护了 g,算法仍然是 O(n2) 的不能接受。还需要再套一层。
于是引入一个 Gv=max0k<i,ak=v{gk},则有 fi=Gbj1+pi。我们尝试动态维护 Gxx=0n)。

因为 G 的变化是基于 g 的变化,我们先研究 g 是如何变化的。

ii+1 的时刻,可能有两种更新:一种是 g0i1 的更新,一种是新增了 gi
对于旧 gk 的改变,都增加了 [aiak][pi>0]pi。对于 pi0 的情况,直接略去,因为不会产生任何贡献;当 pi>0,每个 gk 增加 [akai]pi

对于新增的 gi,容易发现 gi=fi

那么 Gx 的变化是怎么样的呢?对于旧 gk 的改变,容易发现对于 vaiGv 增加 pi;对于新增的 gi,有 Gai=max(Gai,fi)

当我们询问 G,只需要查询 Gv 一个位置的值即可。

所以 G 需要支持:后缀加法、单点取 max、单点查询。

直接线段树当然可以,但是有些大材小用了。单点 max 可以拆成一次查询和两次后缀加法。再把数组 reverse 一下,就变成前缀加法和单点查询,使用 BIT 可以完成。

注意在 ai 对应 b1 的时候特判。

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 5e5 + 5;
const ll INF = 0x3f3f3f3f3f3f3f3fll;

int n, a[N], m, b[N];
ll p[N], sum, f[N];

struct BIT {
	ll c[N];
	
	int lowbit(int x) {
		return x & -x;
	}
	void mdf(int x, ll v) {
		for (; x <= n; x += lowbit(x)) 
			c[x] += v;
	}

	ll qry(int x) {
		ll s = 0;
		for (; x; x -= lowbit(x))
			s += c[x];
		return s;
	}
} T;

int main() {
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	for (int i = 1; i <= n; i++) {
		cin >> p[i];
		sum += p[i];
	}
	cin >> m;
	for (int i = 1; i <= m; i++)
		cin >> b[i];
		
	T.mdf(1, -INF);
	for (int i = 1; i <= n; ++i) {
		int j = lower_bound(b + 1, b + 1 + m, a[i]) - b;
		if (j <= m && a[i] == b[j]) { //是b数组内的 
			if (j == 1)
				f[i] = p[i];
			else
				f[i] = T.qry(b[j - 1]) + p[i];
		}
		else
			f[i] = ~INF;
		if (p[i] > 0)
			T.mdf(a[i], p[i]);
		ll tmp = T.qry(a[i]);
		if (f[i] > tmp) {
			T.mdf(a[i], f[i] - tmp);
			T.mdf(a[i] + 1, tmp - f[i]);
		}
	}
	ll ans = T.qry(b[m]);
	if (ans > -1e15) {
		puts("YES");
		cout << sum - ans << endl;
	}
	else
		puts("NO");
	return 0;
}
posted @   FLY_lai  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示