题目:luogu2678.
题目大意:给定一个长度为
n
n
n的序列
a
i
a_i
ai和
a
0
a_0
a0以及
a
n
+
1
a_{n+1}
an+1,要求选择一个长度不超过
m
m
m的位置序列
p
i
(
1
≤
p
i
≤
n
)
p_i(1\leq p_i\leq n)
pi(1≤pi≤n)使得
min
i
=
1
n
+
1
{
a
i
−
a
i
−
1
}
\min_{i=1}^{n+1}\{a_{i}-a{i-1}\}
mini=1n+1{ai−ai−1}最大.
1
≤
m
≤
n
≤
5
∗
1
0
4
1\leq m\leq n\leq 5*10^4
1≤m≤n≤5∗104.
显然二分答案 m i d mid mid,考虑如何判定.
一个简单的贪心想法是,直接枚举过去,如果当前保留的 a l a s t a_{last} alast和现在枚举到的 a i a_i ai的差小于 m i d mid mid,则不保留,否则保留并更新 l a s t last last,计算出需要删除的数即可判定.
时间复杂度 O ( n log n ) O(n\log n) O(nlogn).
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=50000,INF=(1<<30)-1;
int n,m,a[N+9];
void into(){
int t;
scanf("%d%d%d",&t,&n,&m);
for (int i=1;i<=n;++i)
scanf("%d",&a[i]);
a[++n]=t;
}
bool Check(int mid){
int lst=0,cnt=0;
for (int i=1;i<=n;++i)
a[i]-lst<mid?++cnt:lst=a[i];
return cnt<=m;
}
int Two_divide(){
int l=0,r=INF,mid=l+r+1>>1;
for (;l<r;mid=l+r+1>>1)
Check(mid)?l=mid:r=mid-1;
return l;
}
void outo(){
printf("%d\n",Two_divide());
}
int main(){
into();
outo();
return 0;
}