Link
虽然在cf上ac了但评论区指出了我的错误,有空再改2333
题意:
给出一个有n个珠子的项链,需要分成m段,使得给出的m个数每个数都处在单独一段,输出最长段的最小长度。
1 <= m < n < 1e18, m <= 1e6 保证mi按递增顺序给出
思路:
显然,二分答案,一开始没有注意是项链,每次check贪心地从0开始,cur表示当前的位置,每一步若cur + mid < a[i],则return false,否则cur = min(cur + mid, a[i+1]-1),wa了。改进的时候加了一个偏移量delta,具体见代码。
一开始的代码虽然过了原题目,但仍然有bug,经评论区大佬指正后修改,然而还是错的
// Decline is inevitable,
// Romance will last forever.
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxm = 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;
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 n, m;
int a[maxm];
bool ok(int mid) {
int cur = a[1] - 1; //cur从a[1]的前一位开始 把a[1]看作第1位
int delta = 0; //delta表示初始位置最多可以向左(后)移几位
for(int i = 1; i < m; i++) {//循环m-1次,剩最后一个m不用考虑
//因为最后一步一定要和第一步接上,所以其实是确定的
if(cur + mid < a[i]) //如果够不到下一个,则mid不符合题意,继续二分
return false;
//delta = max(delta, mid - (a[i] - cur)); 错误代码
delta = max(delta, mid - (a[i+1] - cur - 1));
//mid表示能走的步数,括号内表示实际走的步数(只能走到下下个的前一位),差即为delta
cur = min(cur + mid, a[i+1]-1);//如果够得到下一个,则最多到下下个的前一位
}
int cnt = n + a[1] - 1; //相当于把a[1]前的位数补到了尾端
if(cnt - cur > mid + delta) return false; //如果最后一步长度大于mid + delta 则false
return true;
}
void solve() {
read(n);
read(m);
for(int i = 1; i <= m; i++)
read(a[i]);
int l = 1, r = n;
int ans = n;
while(l <= r) {
int mid = (l + r) >> 1;
if(ok(mid)) {
ans = mid;
r = mid - 1;
}
else l = mid + 1;
}
printf("%lld\n", ans);
}
signed main() {
solve();
return 0;
}