您的位置:首页 > 其它

【bzoj4590】[Shoi2015]自动刷题机 二分

2017-10-31 17:15 288 查看
题目描述

一个数,初始为 0 。 l 次操作,每次给这个数加上 xi ( xi 可能为负),如果其小于 0 则变成 0 ,如果大于等于 n 则变成 0 并给 ans 加 1 。已知最后的 ans 等于 k ,求 n 可能的最小值和最大值。如果没有满足条件的 n ,输出 -1 。

输入

第一行两个整数 l,k,表示刷题机的日志一共有 l 行,一共了切了 k 题。
第二行 l 个整数,x1…xl。xi>=0表示写了 xi 行代码。xi<0 表示删除了这道题的 -xi 行代码。
1<=l,k<=100000,|xi|<=10^9
输出

输出两个数 a,b。分别代表 n 可能的最小值和最大值。如果不存在这样的 n 则输出 -1 。
样例输入

4 2

2

5

-3

9

样例输出

3 7

题解

二分

显然随着 ans(n) 的增加,答案单调不增长。。。于是二分。。。没了。。。

二分答案,直接模拟判断能否满足条件。

求最小值时二分最小的ans,使得结果小于等于k;求最大值时二分最大的ans,使得结果大于等于k。

注意二分出来结果以后需要代入检验一下结果是否等于k,因为求的是结果小于等于k的,可能取不到k。

时间复杂度$O(n\log a)$

#include <cstdio>
typedef long long ll;
ll a[100010];
int n;
int solve(ll mid)
{
int i , ans = 0;
ll now = 0;
for(i = 1 ; i <= n ; i ++ )
{
now += a[i];
if(now < 0) now = 0;
if(now >= mid) now = 0 , ans ++ ;
}
return ans;
}
int main()
{
int i , m;
ll l , r , mid , ans;
scanf("%d%d" , &n , &m);
for(i = 1 ; i <= n ; i ++ ) scanf("%lld" , &a[i]);
l = 1 , r = 1000000000000000ll , ans = -1;
while(l <= r)
{
mid = (l + r) >> 1;
if(solve(mid) <= m) ans = mid , r = mid - 1;
else l = mid + 1;
}
if(ans == -1 || solve(ans) != m) puts("-1");
else
{
printf("%lld " , ans);
l = 1 , r = 1000000000000000ll , ans = -1;
while(l <= r)
{
mid = (l + r) >> 1;
if(solve(mid) >= m) ans = mid , l = mid + 1;
else r = mid - 1;
}
printf("%lld\n" , ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: