金牌厨师 (二分+差分)

金牌厨师

[Link](K-金牌厨师_第九届“图灵杯”NEUQ-ACM程序设计竞赛个人赛 (nowcoder.com))

题意

给定 n n n个区间,选取一些区间使得 m a x ( m i n ( k ( 区 间 个 数 ) , l e n ( 区 间 交 集 长 度 ) ) ) max(min(k(区间个数),len(区间交集长度) )) max(min(k(),len()))

思路

答案是某个区间长度,假设最优解为 m i n ( k , l e n ) = = r e s min(k,len)==res min(k,len)==res,那么 r e s − 1 res-1 res1一定满足条件。

  • l e n = r e s len=res len=res, 那么我们将区间长度变小,那么交集内的区间个数只会增多或不变,因此成立
  • k = r e s k=res k=res,我们减少区间个数那么区间交集会变大或不变,因此 r e s = k − 1 res=k-1 res=k1

所以具有二段性,可以二分。

我们来二分区间交集长度 l e n len len,判断是否存在长度为 l e n len len的区间且区间个数 ≥ l e n \ge len len

可以通过差分差分数组 d d d来维护当前位置是否存在连续大于 l e n len len的区间,我们枚举每一个区间的左端点 l l l,如果区间长度 l i n e ≥ l e n line\ge len linelen,我们就在 d [ l + l e n − 1 ] d[l+len-1] d[l+len1]加一, d [ r + 1 ] d[r+1] d[r+1]减一,表示当前区间内存在连续大于 l e n len len的区间贡献一下,求一个前缀和就可以当前位置 ≥ l e n \ge len len区间的个数了。

Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <unordered_map>
#include <cmath> 
#include <stack>
#include <iomanip>
#include <deque> 
#include <sstream>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e6 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
#define tpyeinput int
inline char nc() {static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;}
inline void read(tpyeinput &sum) {char ch=nc();sum=0;while(!(ch>='0'&&ch<='9')) ch=nc();while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+(ch-48),ch=nc();}
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
    e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
PII a[N];
int d[N];
bool check(int x) {
	for (int i = 1; i <= m + 1; i ++) d[i] = 0;
	for (int i = 0; i < n; i ++) 
		if (a[i].y - a[i].x + 1 >= x) d[a[i].x + x - 1] ++, d[a[i].y + 1] --;
	int now = 0;
	for (int i = 1; i <= m + 1; i ++) {
		d[i] += d[i - 1];
		if (d[i] >= x) return true;
	}
	return false;
}
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> m >> n;
    for (int i = 0; i < n; i ++) cin >> a[i].x >> a[i].y;
    int l = 0, r = min(n, m), res = 1;
    while (l < r) {
    	int mid = l + r + 1 >> 1;
    	if (check(mid)) l = mid;
    	else r = mid - 1;
    }
    cout << l << endl;
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值