题目链接

题目大意:\(x\)轴的整点上有一些不同种类的珠子,求一个最短长度\(ans\),使得有一个长为\(ans\)的区间包含所有种类珠子

尺取法,二分


分析:
首先我们答案是满足单调性的,如果短区间符合要求那么长区间一定也满足

所以我们可以考虑二分

关于二分的\(check\)可以用类似单调队列的方式实现(也就是尺取法)

我们维护两个指针\(i\),\(j\)每次往右移动一步\(j\),随后把\(i\)也一直往右移,直到\(i\),\(j\)所指的珠子构成的区间符合要求即可,在这个过程中维护一下颜色种类

复杂度\(O(nlog\max\{pos\})\),\(pos\)为珠子位置

代码:

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cctype>
using namespace std;
const int maxn = 1e6 + 100;
inline int read(){
	int x = 0;char c = getchar();
	while(!isdigit(c))c = getchar();
	while(isdigit(c))x = x * 10 + c - '0',c = getchar();
	return x;
}
struct Node{
	int pos,opt;
	bool operator < (const Node &rhs)const{return pos < rhs.pos;}
}val[maxn];
int cnt[64],q[maxn],tot,now_col,n,k;
inline void ins(int x){if(!(cnt[x]++))now_col++;}
inline void del(int x){if(!(--cnt[x]))now_col--;}
inline bool check(int len){
	now_col = q[0] = 0;memset(cnt,0,sizeof(cnt));
	int head = 0,tail = 0;
	for(int i = 1;i <= tot;i++){
		while(head <= tail && val[q[head]].pos < val[i].pos - len)del(val[q[head++]].opt);//右移i
		ins(val[i].opt);
		q[++tail] = i;//右移j
		if(now_col == k)return true;
	}
	return false;
}
int main(){
	n = read(),k = read();
	for(int i = 1;i <= k;i++){
		int x = read();
		while(x--)val[++tot] = Node{read(),i};
	}
	sort(val + 1,val + 1 + tot);
	int l = 0,r = 0x7fffffff - 1,ans = -1;
	while(l <= r){
		int mid = (l + r) >> 1;
		if(check(mid))ans = mid,r = mid - 1;
		else l = mid + 1;
	}
	printf("%d\n",ans);
	return 0;
}

相关文章:

  • 2021-05-30
  • 2021-10-16
  • 2021-12-04
  • 2021-08-08
  • 2021-05-23
  • 2021-12-21
  • 2022-12-23
  • 2021-09-12
猜你喜欢
  • 2022-01-23
  • 2021-08-02
  • 2022-12-23
  • 2021-08-25
  • 2021-12-16
  • 2021-09-21
相关资源
相似解决方案