题目描述
曾经发明了信号增幅仪的发明家小 H 又公开了他的新发明“自动刷题机”,一 种可以自动 AC 题目的神秘装置。
自动刷题机刷题的方式非常简单:首先会瞬间得出题目的正确做法,然后开始 写程序。每秒,自动刷题机的代码生成模块会产生以下两种可能的结果之一:
1. 心情很好,写了 xi 行代码;
2. 心情不好,删掉了之前写的 yi 行代码。(如果 yi 大于当前代码长度则相 当于全部删除。)
对于一个 OJ,存在某个固定的正整数长度 n,一旦自动刷题机在某秒结束时 积累了大于等于 n 行的代码,它就会自动提交并 AC 此题,然后新建一个文件 (即弃置之前的所有代码)并开始写下一题。小 H 在某个 OJ 上跑了一天的自 动刷题机,得到了很多条关于写代码的日志信息。他突然发现自己没有记录这 个 OJ 的 n 究竟是多少。所幸他通过自己在 OJ 上的 Rank 知道了自动刷题机 一共切了 K 道题,希望你计算 n 可能的最小值和最大值。
输入
第一行两个整数 L, K,表示刷题机的日志一共有 L 行,一共了切了 K 题。
接下来 L 行,每行一个整数 xi,依次表示每条日志。若 xi ≥ 0,则表示写了 xi 行代码,若 xi < 0,则表示删除了 yi = −xi 行代码。
输出
输出一行两个整数,分别表示 n 可能的最小值和最大值。
注意:如果这样的 n 不存在,请输出一行,这一行只有一个整数 −1。
数据范围限制
Solution:
通过及其复杂的证明(指快两面pdf的证明),蓝鹅考场上随便手推假设了几个情况就可以想到题目符合单调性,即n越大切得题越少
然后就容易想到用二分答案,众所周知,若存在多个答案,通过修改二分策略可以实现查询最大和最小的答案
值得一提的是,就是如何判断输出-1,二分答案不管如何也会能给你找出个答案,所以说我们可以对最后的答案进行check,如何没有正好等于K就输出-1
Code:
1 #include<bits/stdc++.h>
2 using namespace std;
3 #define max(a,b) a>b?a:b
4 int L,K,X[100050];
5 long long Maxx,Minn,Ans;
6 bool Check(long long T,int Mode){
7 long long Deal=0;
8 int Res=0;
9 for(int i=1;i<=L;i++){
10 Deal+=X[i];
11 Deal=(Deal<0)?0:Deal;
12 if(Deal>=T){
13 Deal=0;
14 Res++;
15 }
16 }
17 if(Mode==1){
18 if(Res<=K) return true;
19 else return false;
20 }
21 if(Mode==2){
22 if(Res>=K) return true;
23 else return false;
24 }
25 if(Mode==3){
26 if(Res==K) return true;
27 else return false;
28 }
29 return (1+1==2);
30 }
31 int main()
32 {
33 freopen("automaton.in","r",stdin);
34 freopen("automaton.out","w",stdout);
35 scanf("%d%d",&L,&K);
36 for(int i=1;i<=L;i++){
37 scanf("%d",&X[i]);
38 }
39 //Search Minn
40 long long L=1,R=1e14+7;
41 while(L<=R){
42 long long Mid=(L+R)/2;
43 if(Check(Mid,1)){
44 Ans=Mid;
45 R=Mid-1;
46 }
47 else L=Mid+1;
48 }
49 Minn=Ans;
50 //=============================================
51 //Search Maxx
52 L=1,R=1e14+7;
53 Ans=0;
54 while(L<=R){
55 long long Mid=(L+R)/2;
56 if(Check(Mid,2)){
57 Ans=Mid;
58 L=Mid+1;
59 }
60 else R=Mid-1;
61 }
62 Maxx=Ans;
63 if(!Check(Maxx,3)) cout<<-1;
64 else cout<<Minn<<" "<<Maxx;
65 return 0;
66 }