SHOI2015 自动刷题机
题目链接:戳我
我也想要一个!!!
显然能够看出来单调性——当N越大,能AC的题越少,反之越少。所以。。。很明显的二分答案对吧。
唯一一点不太一样的是,它要求可能的最大值,和可能的最小值。
那我们就写两个check,先求出来最大值,如果算出来的AC题数大于等于K,我们就选择右区间。
然后再0和最大值的区间中再次二分(减小带的log的大小),因为是求最小值,所以如果AC题数小于等于K,我们就选择左区间。
最后注意如果最小值算出来是0的话还是要+1的,因为题目中说要求非负。
什么时候不合法?当最小值大于最大值(为什么会这样?,大家可以手动模拟一下,根据我写的这种二分的原理,如果中间没有==k的,那么便会出现这种情况)或者最小值和最大值都是0的时候。。。就非法啦!
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define MAXN 100010
using namespace std;
int n,k;
int a[MAXN];
long long cur_ans;
inline bool check(long long x)
{
long long sum=0,ans=0;
for(int i=1;i<=n;i++)
{
if(a[i]<0&&sum+a[i]<0) sum=0;
else sum+=a[i];
if(sum>=x)
{
ans++,sum=0;
}
}
if(ans>=k) return true;
else return false;
}
inline bool check2(long long x)
{
long long sum=0,ans=0;
for(int i=1;i<=n;i++)
{
if(a[i]<0&&sum+a[i]<0) sum=0;
else sum+=a[i];
if(sum>=x) ans++,sum=0;
}
if(ans>k) return true;
else return false;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
long long l=0,r=(long long)1e14;
while(l<r)
{
long long mid=(l+r)>>1;
if(check(mid)) l=mid+1;
else r=mid;
}
cur_ans=l-1;
r=l,l=0;
while(l<r)
{
long long mid=(l+r)>>1;
if(check2(mid)) l=mid+1;
else r=mid;
}
if((l==0&&cur_ans==0)||(cur_ans<l)){printf("-1\n");return 0;}
if(l==0) l++;
printf("%lld %lld\n",l,cur_ans);
return 0;
}