洛谷 4343 libreoj 2036 bzoj 4590 [SHOI2015]自动刷题机 题解

题意简述

有一个刷题机,记录了这样的信息:有一个长度为$n<=1e5$的序列$a$,表示写(>0)或删(<0)了若干行代码。如果删除的代码行数超过了已有的代码行数,那就是保持为$0$行代码。每当你的代码行数$>m$之后,你就会自动AC一个题,代码清空。现在已知你AC了$k$个题。求$m$的范围。无解输出-1.

思路

很明显,$m$越大$AC$的越少。二分即珂。(话说上海的题怎么这么水)

实现注意

我们怎么判断mid是取$(l+r+1)/2$还是$(l+r)/2$呢?

我刚开始学二分的时候也为这个事情发愁。但是后来我发现一个简单易懂的理解方法。

因为我经常会调试。调试发现,就是$r=l+1$的时候陷入了一个死循环。

我们想想,$r=l+1$的时候,$(l+r)/2$相当于$l$,$(l+r+1)/2$相当于$r$。(换句话说,就是偏左的$mid$和偏右的$mid$)。然后如果我们的条件是$l=mid$,$mid$还取的是$(l+r)/2=l$,那就相当于没有减小,会死循环。所以当条件是$l=mid$,也就是要取最大值的时候,$mid$应该取$(l+r+1)/2$。

同理,当我们要取最小值的时候,也就是$r=mid$的时候,应该$mid=(l+r)/2$,这样才能让区间缩小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
#define int long long
#define N 155555
#define F(i,l,r) for(int i=l;i<=r;++i)
#define D(i,r,l) for(int i=r;i>=l;--i)
#define Fs(i,l,r,c) for(int i=l;i<=r;c)
#define Ds(i,r,l,c) for(int i=r;i>=l;c)
#define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))
#define MEM(x,a) memset(x,a,sizeof(x))
#define FK(x) MEM(x,0)

void R1(int &x)
{
x=0;char c=getchar();int f=1;
while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=(f==1)?x:-x;
}
int n,k;
int a[N];
void Input()
{
R1(n);R1(k);
F(i,1,n) R1(a[i]);
}

int cnt(int m)//取m时的AC量
{
int S=0,C=0;
F(i,1,n)
{
S+=a[i];
if (S<0) S=0;
if (S>=m) {C++;S=0;}
}
return C;
}
void Soviet()
{
int l=1,r=1e16;
while(l<r)
{
int mid=(l+r)>>1;
int C=cnt(mid);
if (C<k) r=mid-1;//大了
else if (C==k) r=mid;//正好,但是我们要取最小的,因为这边是求最小值
else if (C>k) l=mid+1;//小了
}
if (cnt(l)!=k) {puts("-1");return;} //判一下无解
printf("%lld ",l);//这个时候l==r,所以输出哪个都无妨
//此时l=r=m的最小值

l=1,r=1e16;
while(l<r)
{
int mid=(l+r+1)>>1;
int C=cnt(mid);
if (C<k) r=mid-1; //大了
else if (C==k) l=mid; //正好,但是我们要取最大的,因为这边是求最大值
else if (C>k) l=mid+1; //小了
}
printf("%lld\n",l); //同上
//此时l=r=m的最大值
}

#define Flan void
Flan IsMyWife()
{
Input();
Soviet();
}
#undef int //long long
}
int main()
{
Flandre_Scarlet::IsMyWife();
getchar();getchar();
return 0;
}
w