ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【CF487B】Strip 题解

2022-07-20 09:05:13  阅读:133  来源: 互联网

标签:ch int 题解 CF487B 极差 maxn 端点 Strip rec


Solution

没想到这道题就个 RMQ + 简单 dp。从小到大遍历 \(l\) 到 \(n\),对于每个确定的区间右端点 \(i\),记 \(f_i\) 表示 \([1,i]\) 中最少能分成几段。那么显然,\(f_i = \min(f_j|j\in[1,i - l + 1]) + 1\)。当然,前提是 \(f_j\) 可被分为若干段。

下面先贴上代码,后面会详讲优化及其原因。

(看见前面几篇题解都没有提到这个优化的具体原因。)

#include<bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for(register int i = a; i <= b; ++i)
#define per(i, a, b) for(register int i = a; i >= b; --i)
typedef long long ll ;
const int inf = 2147483647;
inline int rd(){
    int x = 1, s = 0; char ch = getchar();
    while(ch < '0' or ch > '9'){if(ch == '-') x = -1; ch = getchar();}
    while(ch >= '0' and ch <= '9') s = s * 10 + ch - '0', ch = getchar();
    return x * s;
}
inline void wr(int x){
    if(x < 0) putchar('-'), x *= -1;
    if(x > 9) wr(x / 10);
    putchar(x % 10 + '0');
}
const int maxn = 1e5 + 5;
//----------------------------------//
int n, l, s;
int mn[maxn][30], mx[maxn][30], rec;
int lg[maxn], f[maxn];

inline void pre(){
	for(int i = 1; (1 << i) <= n; ++i)
		for(int j = 1; j + (1 << i) - 1 <= n; ++j)
			mn[j][i] = min(mn[j][i - 1], mn[j + (1 << (i - 1))][i - 1]),
			mx[j][i] = max(mx[j][i - 1], mx[j + (1 << (i - 1))][i - 1]);
}

inline int chck(int L, int R){
	int k = 0;
	while((1 << (k + 1)) <= R - L + 1) k += 1;
	int mi = min(mn[L][k], mn[R - (1 << k) + 1][k]);
	int ma = max(mx[L][k], mx[R - (1 << k) + 1][k]);
	return ma - mi;
}
	
int main(){
	n = rd(), s = rd(), l = rd();
	rep(i, 1, n) f[i] = inf, mx[i][0] = mn[i][0] = rd();
	pre();
	rep(i, l, n){
		while(i - rec + 1 > l and ((f[rec] == inf) or (chck(rec + 1, i) > s)))
			rec += 1;
		if(i - rec + 1 > l) f[i] = min(f[i], f[rec] + 1);
	}
	if(f[n] != inf) wr(f[n]);
	else wr(-1);
}

在上面的代码中可以看到具体实现。这里有个优化:为什么每次枚举到一个新的右端点,不需要从头再选一次 \(f\) 值最小的左端点 \(j\) 呢?这时候要注意到一个很重要的性质:对于一个区间 \([p,q]\),若将 \(q+1\) 这个节点也加进来,它要么对这个区间的极差没有影响,要么只会将这个极差变得更大。所以,若是一个左端点 \(j\),满足区间 \([j,i-1]\) 的极差大于 \(s\),那么区间 \([j,i]\) 的极差也必定大于 \(s\)(其他情况同理)。同时,左端点 \(j\) 越往右,\(f_j\) 只会不变或更大。

综上,我们只需要继续上一个枚举的 \(i\) 的左端点的位置往后枚举新的左端点,并且取最左边的合法左端点即可。


感谢阅读。

辛苦管理员审核,如有问题烦请指出。

标签:ch,int,题解,CF487B,极差,maxn,端点,Strip,rec
来源: https://www.cnblogs.com/gsn531/p/16496522.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有