【BZOJ2600】[Ioi2011]ricehub 双指针法

【BZOJ2600】[Ioi2011]ricehub

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

Sample Output

3
HINT
1 ≤ R ≤ 100,000
1 ≤ L ≤ 1,000,000,000
0 ≤ B ≤ 2,000,000,000,000,000

题解:网上好多用二分的,但是双指针多优美啊~

显然,如果我们确定了收获[l,r]中的所有稻田,那么将谷仓建在它们的中位数位置是最优的。所以用前缀和维护一下,就能快速求出[l,r]需要的运费,接着就能用双指针法了。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn=100010;
int n,ans;
ll m;
ll x[maxn],s[maxn];
bool calc(int l,int r)
{
	int mid=(l+r)>>1;
	return (s[r]-s[mid])-(r-mid)*x[mid]+(mid-l)*x[mid]-(s[mid-1]-s[l-1])<=m;
}
inline ll rd()
{
	ll ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret*f;
}
int main()
{
	n=rd(),rd(),m=rd();
	int i,j;
	for(i=j=1;i<=n;i++)
	{
		x[i]=rd(),s[i]=x[i]+s[i-1];
		for(;!calc(j,i);j++);
		ans=max(ans,i-j+1);
	}
	printf("%d",ans);
	return 0;
}
 
原文地址:https://www.cnblogs.com/CQzhangyu/p/7575613.html