题意:
- 有n间宿舍实施宵禁:
- 1.一个舍监从1走向n,另一个舍监从n走向1
- 2每个宿舍有
a[i]
a
[
i
]
个学生,且
∑ni=1a[i]=n∗b
∑
i
=
1
n
a
[
i
]
=
n
∗
b
- 3舍监走到某个宿舍前,未上锁宿舍的学生可以走到距离当前宿舍不超过d的宿舍
- 4舍监查某个宿舍时,如果宿舍人数
<b
<
b
<script type="math/tex" id="MathJax-Element-1197">
- 5所有宿舍上锁,结束
- 6如果n是奇数,第
n/2+1
n
/
2
+
1
个宿舍归第一个舍监查
想法:
- 首先如果
i<a<b<j
i
<
a
<
b
<
j
那么只会a向i走,b向j走,不会a向j走时,b向i走
- 所以宿舍中会有一道分界线,一部分往左走,一部分往右走
- 假设只有左边一个舍监
- 那么查到第i个舍监时,如果能把一部分人调过来使
a[i]⩾b
a
[
i
]
⩾
b
那就把那部分人调过来使得
a[i]=b
a
[
i
]
=
b
,否则就令该宿舍所有人去第i+1间宿舍
- 判断即
sum[i∗d]−cnt∗b⩾b
s
u
m
[
i
∗
d
]
−
c
n
t
∗
b
⩾
b
,cnt为前面宿舍人数
=b
=
b
的个数
- 令
l=i∗d,r=n−i∗d,mid=n/2
l
=
i
∗
d
,
r
=
n
−
i
∗
d
,
m
i
d
=
n
/
2
- 如果
l<r
l
<
r
,那么1~l的人都尽力满足第i间,r~n的人满足第n-i+1间
- 如果
r<l
r
<
l
呢,r~l这部分人往哪跑
- 注意条件
∑ni=1a[i]=n∗b
∑
i
=
1
n
a
[
i
]
=
n
∗
b
- 加入让mid~l这部分人往i跑,似乎会令右边的
cnt1−−
c
n
t
1
−
−
,
- 但跑的情况是因为
sum[mid]<=b∗cnt+b
s
u
m
[
m
i
d
]
<=
b
∗
c
n
t
+
b
,因为
cnt<=mid
c
n
t
<=
m
i
d
,所以
sum[mid]<=b∗mid
s
u
m
[
m
i
d
]
<=
b
∗
m
i
d
- 所以
sum[n]−sum[mid]>=mid∗b
s
u
m
[
n
]
−
s
u
m
[
m
i
d
]
>=
m
i
d
∗
b
,所以右边那部分人对付第二个舍监绰绰有余
- 所以直接贪心
- 如果n是奇数,那么第
n/2+1
n
/
2
+
1
间宿舍肯定可以满足
using namespace std;
const ll maxN=1e5+10;
ll n,d,k,a[maxN],sum[maxN],cnt1,cnt,b,i,ans,x;
int main(){
//freopen("a.in","r",stdin);
scanf("%I64d%I64d%I64d",&n,&d,&b);
fo(i,1,n) scanf("%I64d",&a[i]),sum[i]=sum[i-1]+a[i];
fo(i,1,n/2){
x=sum[min(n,i*d+i)]-cnt*b;
if (x>=b) cnt++;
x=sum[n]-sum[max(n-i*d-i,0)]-cnt1*b;
if (x>=b) cnt1++;
}
ans=n/2-min(cnt,cnt1);
printf("%I64d",ans);
}