題目: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;
}