2600: [Ioi2011]ricehub
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 628 Solved: 325
[Submit][Status][Discuss]
Description
乡间有一条笔直而长的路称为“米道”。沿着这条米道上 R 块稻田,每块稻田的坐标均
为一个 1 到 L 之间(含 1 和 L)的整数。这些稻田按照坐标以不减的顺序给出,即对于 0 ≤ i <
R,稻田 i 的坐标 X[i]满足 1 ≤ X[0] ≤ ... ≤ X[R-1] ≤ L。
注意:可能有多块稻田位于同一个坐标上。
我们计划建造一个米仓用于储存尽可能多的稻米。和稻田一样,米仓将建在米道上,其
坐标也是一个 1 到 L 之间的整数(含 1 和 L)。这个米仓可以建在满足上述条件的任一个位
置上,包括那些原来已有一个或多个稻田存在的位置。
在收获季节,每一块稻田刚好出产一滿货车的稻米。为了将这些稻米运到米仓,需要雇
用一位货车司机来运米。司机的收费是每一满货车运送一个单位的距离收取 1 元。換言之,
将稻米从特定的稻田运到米仓的费用在数值上等于稻田坐标与米仓坐标之差的绝对值。
不幸的是,今年预算有限,我们至多只能花费 B 元运费。你的任务是要帮我们找出一个
建造米仓的位置,可以收集到尽可能多的稻米。
Input
第一行 三个整数 R L B
接下来R行 每行一个整数 表示X[i]
Output
一个整数 最多稻米数
Sample Input
5 20 6
1
2
10
12
14
1
2
10
12
14
Sample Output
3
HINT
1 ≤ R ≤ 100,000
1 ≤ L ≤ 1,000,000,000
HINT
1 ≤ R ≤ 100,000
1 ≤ L ≤ 1,000,000,000
0 ≤ B ≤ 2,000,000,000,000,000
这个题目居然在我们学校讲课时被归类为了二分(没认真听课QAQ不知道是怎么兹磁的啊)%%
显然易得出我们选取的米仓一定收集的一段连续的区间,而米仓一定是在这段区间的中位数上。
我们将右区间r从1到R枚举,每一次维护的左区间l。
记res为剩余的钱数。如果res小于0则左区间右移(即序列最早入队的稻田出队),直到res大于0。中位数可以O(1)的转移。
关于复杂度:因为每一个稻田至多只有入队和出队两次操作,所以复杂度为O(n)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cmath>
#include<queue>
#define llg long long
#define yyj(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout);
#define maxn 100010
using namespace std; llg sc()
{
llg i=;char c=getchar();
while(c>''||c<'')c=getchar();
while(c>=''&&c<='')i=i*+c-'',c=getchar();
return i;
} llg x,i,j,k,n,l,r,mid,m,a[maxn],ans;
double res,b,wz,lastwz;
int main()
{
yyj("a");
cin>>n>>m>>b;
for (i=;i<=n;i++) a[i]=sc();
res=b;
x=;
ans=;
l=; lastwz=a[];
for (r=;r<=n;r++)
{
if (a[r]>m) break;
x++;
if (x % ) wz=a[l+x/+]; else wz=(double)(a[l+x/]+a[l+x/+])/;
if (x % ==) res-=(wz-lastwz);
res-=a[r]-wz; lastwz=wz;
while (res<)
{
x--; l++; res+=lastwz-a[l];
if (x % ) wz=a[l+x/+]; else wz=(a[l+x/]+a[l+x/+])/;
if (x % ) res+=wz-lastwz;
lastwz=wz;
}
ans=max(ans,x);
}
cout<<ans;
return ;
}