2021CCPC广州站C. Necklace

题目: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;
}
上一篇:LeetCode - 解题笔记 - 114 - Flatten Binary Tree to Linked List


下一篇:2021/11月笔记:unit test复习6(邮件自动发送2)