题解 洛谷 P4343 [SHOI2015]自动刷题机

自己的第一道\(SHOI\)题目\(QAQ\)

题目传送门

我们来看题,题意大概是:让你求出正整数\(n\),使得将给定数列分成\(k\)段,按照题目所述方法计算后每一段的和都大于等于\(n\)的最大值和最小值。

如果我们只要计算最大值,这题就可以转化为一个与\(P1182 数列分段 Section II\)相似的二分模型。

需要注意的是,当用\(mid\)得出的答案大于等于\(m\)时,我们应该把\(l\)移至\(mid\)以得到最大值,并用\(ans\)记录。因为\(check(mid)>m\)时答案一定是偏小的,而\(=\)时不一定是最大值。

代码如下:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int read(){
	int w=0,h=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')h=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){w=w*10+ch-'0';ch=getchar();}
	return w*h;
}
int n,m,x[100010],l,r,ans;
int check(int mid){
	int cnt=0,sum=0;
	for(int i=1;i<=n+1;i++){
		sum+=x[i];
		if(sum<0)sum=0;
		if(sum>=mid)cnt++,sum=0;
	}
	return cnt;
}
signed main(){
	n=read();m=read();
	for(int i=1;i<=n;i++)x[i]=read(),r+=abs(x[i]);
	r++;
	while(l+1<r){
		int mid=l+r>>1;
		if(check(mid)>=m)l=mid,ans=l;
		else r=mid;
	}
	printf("%lld",ans);
	return 0;
}

接下来考虑最小值:由于我们已经求出了最大值,所以最小值一定在0~ans之间(ans是之前求出的最大值),可以继续使用二分求解.特别的,我们仅当check(mid)=m时才把r移至mid,因为刚开始r必定是在答案区间内的,所以check(r)无论如何都不会>m,最后输出r即可。

对于无解情况:如果在第一次求解最大值时记录的ans为0,必定无解。如果第二次求解后最小值r大于最大值ans,同样无解

部分细节会在代码中说明。

AC代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int read(){
	int w=0,h=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')h=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){w=w*10+ch-'0';ch=getchar();}
	return w*h;
}
int n,m,x[100010],l,r,ans;
int check(int mid){//check函数使用int方便两次二分的判断
	int cnt=0,sum=0;
	for(int i=1;i<=n+1;i++){
		sum+=x[i];
		if(sum<0)sum=0;//题目中说明了若已写代码行数小于删除的行数则视为全部删除
		if(sum>=mid)cnt++,sum=0;//写完一题则舍弃之前的代码。
	}
	return cnt;
}
signed main(){
	n=read();m=read();
	for(int i=1;i<=n;i++)x[i]=read(),r+=abs(x[i]);//因为k可能=1,此时n可能为总代码长度。
    r++;//由于个人习惯l+1<r,所以二分之前r必须加1(具体可百度各种二分写法,一些博客中会有说明)
	while(l+1<r){//个人习惯写法
		int mid=l+r>>1;
		if(check(mid)>=m)l=mid,ans=l;
		else r=mid;
	}
	if(ans==0){
		puts("-1");
		return 0;
	}//第一种无解情况
	l=0;//由于最后输出的是r,所以如果l=1,而答案n正好是1,会得不到正确答案
	while(l+1<r){
		int mid=l+r>>1;
		if(check(mid)==m)r=mid;
		else l=mid;
	}
	if(r>ans){
		puts("-1");
		return 0;
	}//第二种无解情况
	printf("%lld %lld",r,ans);
	return 0;
}

blog推销

posted @ 2021-11-04 13:55  pidan007  阅读(53)  评论(0编辑  收藏  举报