首页 > 其他分享 >[题解] CF474E Pillars

[题解] CF474E Pillars

时间:2023-10-05 12:00:13浏览次数:35  
标签:CF474E ma int 题解 Pillars ge 绝对值 序列

题意

给定长度为 \(n\) 的序列 \(a\) 和常数 \(d\),输出一个最长的 \(a\) 的子序列,使得相邻两项的差的绝对值大于等于 \(d\)。

\(n\le10^5\)

题解

数据结构优化 DP 的板子题了吧。

首先,这道题看上去就很 LIS,我们尝试着用类似 LIS 的思路去做。

设 \(f_i\) 表示以 \(i\) 结尾的符合条件的子序列的最大长度,因为还要输出方案,所以务必再设 \(g_i\) 表示这个方案是从 \(g_i\) 处转移来的。

状态转移方程就很好设了:

\[f_i = \max_{j < i,|a_i - a_j| \ge d}f_j + 1 \]

什么都很好处理,除了中间那个绝对值。

所以我们套路的把绝对值拆开,得到:\(a_i - a_j \ge d,a_j - a_i\ge d\)。

我们把 \(a_j\) 单独放在一边,整理得到: \(a_j\le a_i - d,a_j \ge a_i + d\)。

为什么不把 \(a_i\) 单独挑出来?因为后期非常难维护!

我们发现,这个整理得出的式子似乎很好弄?没错,只需要建一棵权值线段树,把每次求完的 \(f_i\) 放到 \(a_i\) 的位置上;查询的时候,我们只要求 \([1,a_i - d] \cup [a_i + d,V]\) 中的最大值即可,其中 \(V\) 是值域。

\(a_i\) 非常大,需要离散化处理一下。

点击查看代码
#include <bits/stdc++.h>
#define P pair<int,int>
using namespace std;


const int N = 1e5 + 5;

int n,d,f[N],g[N];

long long a[N],b[N];

struct Seg{
	int l,r;
	P dat;
}t[N << 2];

void build(int p,int l,int r){
	t[p].l = l, t[p].r = r;
	if (l == r) return ;
	int mid = (l + r) >> 1;
	build(p << 1,l,mid), build(p << 1 | 1,mid + 1,r);
}

void modify(int p,int x,P v){
	if (t[p].l == t[p].r) { t[p].dat = max(t[p].dat,v); return ; }
	int mid = (t[p].l + t[p].r) >> 1;
	if (x <= mid) modify(p << 1,x,v);
	else modify(p << 1 | 1,x,v);
	t[p].dat = max(t[p << 1].dat,t[p << 1 | 1].dat);
}

P query(int p,int l,int r){
	if (l <= t[p].l && t[p].r <= r) return t[p].dat;
	int mid = (t[p].l + t[p].r) >> 1; P ma = {0,0};
	if (l <= mid) ma = max(ma,query(p << 1,l,r));
	if (r > mid) ma = max(ma,query(p << 1 | 1,l,r));
	return ma;
}

void print(int x){
	if (g[x] == 0){
		cout << x << ' ';
		return ;
	}
	print(g[x]);
	cout << x << ' ';
}

int main(){
	cin >> n >> d;
	for (int i = 1;i <= n;i++) cin >> a[i], b[i] = a[i];
	sort(b + 1,b + n + 1);
	int m = unique(b + 1,b + n + 1) - b - 1;
	build(1,1,m);
	int ans = 0;
	for (int i = 1;i <= n;i++){
		int x = lower_bound(b + 1,b + m + 1,a[i]) - b,
			l = upper_bound(b + 1,b + m + 1,a[i] - d) - b - 1,
			r = lower_bound(b + 1,b + m + 1,a[i] + d) - b;
		P res = max({{0,0},query(1,1,l),query(1,r,m)});
		f[i] = res.first + 1;
		g[i] = res.second;
		modify(1,x,{f[i],i});
		ans = max(ans,f[i]);
	}
	cout << ans << '\n';
	for (int i = 1;i <= n;i++)
		if (f[i] == ans)
			return print(i),0;
}

标签:CF474E,ma,int,题解,Pillars,ge,绝对值,序列
From: https://www.cnblogs.com/y1wei/p/cf474e.html

相关文章

  • 题解 accoders::NOI 5510【飞翔的胖鸟(fly)】
    题解accoders::NOI5510【飞翔的胖鸟(fly)】problem求\(f(x)=\frac{ah}{\sin(x)}+bx\)在\((0,\frac\pi2]\)上的最小值。solution\(\sin'(x)=cos(x);\cos'(x)=-\sin(x)\)。\((f(x)\cdotg(x))'=f'(x)g(x)+f(x)g'(x)\)。\(\left(\dfrac{f......
  • 题解 accoders::NOI 5508【漂亮大厨(cook)】
    题解accoders::NOI5508【漂亮大厨(cook)】part1区间加\(x\),区间询问有多少个数字\(\leqy\)。\(n,m\leq10^5,x\leq200,y\leq10^7\)。考虑P5356[Ynoi2017]由乃打扑克的做法,分块,块内按照值排序。修改就整块打tag,散块暴力重构(可以归并排序重构);询问在整块上二分,散块暴力......
  • P9019 [USACO23JAN] Tractor Paths P 题解
    Description有\(n\)个区间,第\(i\)个区间为\([l_i,r_i]\)。保证\(l_1<l_2<\cdots<l_n\)且\(r_1<r_2<\cdots<r_n\)。其中一部分区间是特殊的,输入会给定。如果第\(i\)个区间和第\(j\)个区间相交,那么\(i,j\)之间有一条边。保证\(1,n\)联通。给定\(Q\)组询问,每次......
  • 题解 P9701【[GDCPC2023] Classic Problem】
    题如其名,确实挺经典的。我们称边权在输入中给定的边为特殊边,其它边为平凡边。称特殊边涉及到的点为特殊点,其它点为平凡点。显然,对于连续的若干平凡点\([l,r]\),他们内部的最优连边方式就是连成一条链,花费\(r-l\)的代价。我们先把这样的代价加到答案中,然后将极长连续平凡点缩成......
  • [SHOI2009] 会场预约 题解
    LG任意时刻每个点最多被一条线段覆盖暴力删每条线段是对的插入\([l,r]\)时需要删除的线段要么被\([l,r]\)包含,要么覆盖\(l\)或\(r\)性质非常强所以做法非常多一种比较神奇的:对于两条线段\([l_{1},r_{1}],[l_{2},r_{2}]\),定义<为\(r_{1}<l_{2}\),即线段\(1\)完......
  • 题解 accoders::NOI 5511【漂亮轰炸(bomb)】
    题解accoders::NOI5511【漂亮轰炸(bomb)】http://47.92.197.167:5283/contest/406/problem/4BZOJ3252是弱化版。problem一棵树,边带权。\(Q\)次询问,给定\(k\)和一个首都点,选择\(k\)条路径轰炸,其中必须由一轮要轰炸首都,但没有要求每条路径都经过首都。每条边只能被炸一次,......
  • 题解 P9695【[GDCPC2023] Traveling in Cells】
    显然,询问的答案即为\(x\)所在的极长的满足颜色均在\(\mathbb{A}\)内的连续段的权值和。如果我们能维护对颜色的单点修改,以及求出某个位置所在极长连续段的左右端点\(l,r\),只需要树状数组即可求出答案。一个朴素的想法是对每种颜色开一棵线段树,单点修改是平凡的,极长连续段左......
  • 题解 P9702【[GDCPC2023] Computational Geometry】
    这题一看就不是计算几何,考虑区间DP。设凸多边形的\(n\)个顶点依次为\(P_1,P_2,\cdots,P_n\)。设\(f_{i,j}\)在\(i<j\)时表示\(P_i,P_{i+1},\cdots,P_{j-1},P_j\)组成的多边形的直径的平方,在\(i>j\)时表示\(P_i,P_{i+1},\cdots,P_n,P_1,\cdots,P_{j-1},P_j\)组......
  • 题解 P9697【[GDCPC2023] Canvas】
    好题。后面的操作会覆盖前面的操作,这东西不好处理,我们不妨时光倒流,将问题转化为一个位置一旦被填了数,就再也不会变了。如果解决了这个问题,只需将操作序列倒过来,就得到了原问题的解。显然,所有\(x_i=y_i=2\)的操作会最先被执行,所有\(x_i=y_i=1\)的操作会最后被执行。只需要给......
  • 高橋君 题解
    AtCoder天下一プログラマーコンテスト2014本戦高橋君题意给定\(n,k\),求\[\sum\limits_{i=0}^{k}\dbinom{n}{i}\]多测,\(1\len,k,T\le10^5\)。题解可以考虑使用莫队求解,下文讲述如何移动指针。\(n\rightarrown+1\)根据杨辉三角递推式\(\dbinom{n}{m}=......