题目:C. Necklace
题意:
https://codeforces.com/gym/103415/problem/C
长度为 n 的项链上有 m 个珠子,每个珠子分一段,问最长段长度的最小值
思路:二分+贪心
每次check贪心地从第一个位置开始,所以一开始偏移量最大为:n-a[m]+a[1]-1,mi表示当前起始位置最大的偏移量,每经过一段区间mi要取最小值,不然最开始位置偏移会超过他所在的区间,cnt记录最开始的起始位置一共最大往前的偏移量
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int long long
const int mod=998244353;
const int N=1e6+10;
#define gc()(is==it?it=(is=in)+fread(in,1,Q,stdin),(is==it?EOF:*is++):*is++)
const int Q=(1<<24)+1;
char in[Q],*is=in,*it=in,c;
int n,m;
void read(long long &n){
for(n=0;(c=gc())<'0'||c>'9';);
for(;c<='9'&&c>='0';c=gc())n=n*10+c-48;
}
int a[N];
bool check(int x){
int mi=n-a[m]+a[1]-1;//当前起始位置最大的偏移量
int mm=mi;
int now=0;//用来记录后面一段需要补充前面一段的大小
int cnt=0;//记录最开始的起始位置一共最大往前的偏移量
for(int i=1;i<m;i++){
int xx=x-now;//x-减去要给上一段分配的值表示还能给当前区间分配的值
int cha=a[i+1]-a[i];//当前段的大小
if(xx<=0) return false;//不能再分给后面的区间了就不合法
if(cha>xx){
now=a[i+1]-(a[i]+xx);
mi = min(mi, xx - 1);
}
else{
now=0;
int m1=min(mi,xx-cha);
cnt+=m1;
mi=min(mi-m1,cha-1);
}
}
int ans=now+mm+1-x;//还需要给前面段多少个加上现在这段需要多少个-x=当前段需要分到多少个偏移量
if(x-now>=mm+1||cnt>=ans) return true;//能给最后一段区间分的值>大于最后一段区间大小或者总的能偏移的量>=还需要偏移的量
return false;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
read(n),read(m);
for(int i=1;i<=m;i++){
read(a[i]);
}
int l=1,r=n;
while(l<r){
int mid=(l+r)>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
printf("%lld\n", l);
return 0;
}