ICode9

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

CF1630B Range and Partition

2022-02-03 16:35:25  阅读:175  来源: 互联网

标签:CF1630B Partition xx mid int Range read sn define


首先看到最小化 y − x y-x y−x 这个玩意,果断二分 y − x y-x y−x,显然假如区间更长合法,那么更短一定也合法,然后再枚举 x x x 进而得到 [ x , y ] [x,y] [x,y],接下来的事情就是要判断某一个区间 [ x , y ] [x,y] [x,y] 是否合法。

我们首先把砍成 k k k 段转化为尽可能地多段,因为如果 t t t 段的分割是合法的,我们我们将最后两个区间合并,这就是 t − 1 t-1 t−1 段了。

我们将 a i a_i ai​ 重新赋值,如果 a i ∈ [ x , y ] a_i \in [x,y] ai​∈[x,y] 那么赋值为 1,否则为 -1,这样我们分割的 k k k 段区间每一段的 a i a_i ai​ 的和满足是正数即可,鉴于这是区间求和,搞个前缀和 s i = ∑ j = 1 i a j s_i=\sum\limits_{j=1}^ia_j si​=j=1∑i​aj​,条件变成了 s r − s l − 1 > 0 , s r > s l − 1 s_r-s_{l-1}\gt0,s_r>s_{l-1} sr​−sl−1​>0,sr​>sl−1​, l − 1 l-1 l−1 为刚好上一个区间的右端点,也就是说我们在求一个 s s s 的上升子序列并且长度为 k + 1 k+1 k+1,起点为 s 0 = 0 s_0=0 s0​=0,终点为 s n s_n sn​。于是搞完这一切发现复杂度还是不行。

但是我们发现其实还可以抢救一下,我们发现 s s s 有个奇妙的性质,就是 ∣ s i − s i − 1 ∣ = 1 |s_i-s_{i-1}|=1 ∣si​−si−1​∣=1,所以如果 s s s 里有 x > 0 x>0 x>0,那么 s s s 一定还有 0 , 1 , 2 ⋯ x − 2 , x − 1 0,1,2\cdots x-2,x-1 0,1,2⋯x−2,x−1,并且下标存在在其之前的。这个最长上升子序列是可以构造出来的,只需要中间是连续的正整数。还有最后一个条件那就是序列长度要有 k + 1 k+1 k+1,这很简单只要让 s n ≥ k s_n\ge k sn​≥k 就行。所以我们判定区间合不合法只需要计算一个 s n s_n sn​ 就完了。

回顾 s n s_n sn​ 定义,我们令 t = ∑ i = 1 n [ a i ∈ [ x , y ] ] t=\sum\limits_{i=1}^n[a_i \in [x,y]] t=i=1∑n​[ai​∈[x,y]],显然 s n = t − ( n − t ) = 2 t − n s_n=t-(n-t)=2t-n sn​=t−(n−t)=2t−n,也就是在 [ x , y ] [x,y] [x,y] 的数的个数减去不在的。我们再用一个前缀和便于查询在某个值域区间的数的个数来计算 s n s_n sn​,于是这题就结束了,吗?

我当时以为到这就没了,结果发现题目还让我去求方案,人傻了。这其实也简单,既然都知道了 [ x , y ] [x,y] [x,y],我们可以按照上升子序列的求解方式搞,也可以直接贪心,因为保证了 [ x , y ] [x,y] [x,y] 合法,所以我们区间的和为正的时候就划分一下,显然这是对的。

枚举 [ x , y ] [x,y] [x,y] 貌似也可以用双指针,但是我不会。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define cmin(a, b) (a)=min((a), (b))
#define cmax(a, b) (a)=max((a), (b))
#define mem(a, x) memset(a, x, sizeof(a))
#define rps(i, b, e) for(int i=(b);i<=(e);i++)
#define prs(i, e, b) for(int i=(e);i>=(b);i--)
#define rpg(i, g, x) for(int i=g.head[x];i;i=g.e[i].nxt)
#define opf(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
using namespace std;
template<class T>
inline void read(T &x) {
	x=0;
	bool f=false;
	char c=getchar();
	while(!isdigit(c))f|=(c=='-'), c=getchar();
	while(isdigit(c))x=x*10+(c-'0'), c=getchar();
	if(f)x=-x;
}
const int NR=2e5+10;
int T, n, k, a[NR], s[NR];
int chk(int dif) {
	rps(l, 1, n-dif+1)
		if((s[l+dif]-s[l-1])*2-n>=k)
			return l;
	return 0;
}
struct node {
	int id, v, ct;
}st[NR], p[NR];
int top;
int main() {
	read(T);
	while(T--) {
		read(n), read(k);
		mem(s, 0);
		rps(i, 1, n)read(a[i]), s[a[i]]++;
		rps(i, 1, n)s[i]+=s[i-1];
		int l=0, r=n-1, mid, yx=1e9, xx=1e9;
		while(l<=r) {
			mid=l+r>>1;
			int res=chk(mid);
			if(res==0)l=mid+1;
			else yx=mid, xx=res, r=mid-1;
		}
		printf("%d %d\n", xx, xx+yx);
		int yy=xx+yx;
		l=1;
		int subct=0, ns=0;
		rps(i, 1, n) {
			if(a[i]>=xx && a[i]<=yy)ns++;
			else ns--;
			if(ns<=0 || subct+1>=k)continue;
			printf("%d %d\n", l, i);
			l=i+1, subct++, ns=0;
		}
		printf("%d %d\n", l, n);
	}
	return 0;
}

标签:CF1630B,Partition,xx,mid,int,Range,read,sn,define
来源: https://blog.csdn.net/m0_59024001/article/details/122776668

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

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

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

ICode9版权所有