bzoj4590[Shoi2015]自动刷题机 二分
Posted GXZlegend
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4590[Shoi2015]自动刷题机 二分相关的知识,希望对你有一定的参考价值。
题目描述
一个数,初始为 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; }
以上是关于bzoj4590[Shoi2015]自动刷题机 二分的主要内容,如果未能解决你的问题,请参考以下文章