ricehub bzoj-2600 Ioi-2011
题目大意:在数轴上有r块稻田,稻田坐标为整数。计划建造一个米仓,使得它可以收取尽量多的稻米。米仓的坐标仍需为整数。每一块权值为val的稻田距离米仓的距离为dis,那么收取这个稻田上的大米的代价是val*dis。我们只有b元运费,问最多能收取多少稻米。
注释:$1\le r \le 10^5$,$1\le l\le 10^9$,$0\le b\le 2\cdot 10^{15}$。
想法:这就相当于在一个带权的数轴上选取一个点,使得所有点到该点的加权*距离最小。我们不妨将权值为val的点看成是val个不同的点。那么这就相当于在数轴上$\sum\limits_{i=1}^{r}val_i$个点,所有点到被选取点的距离(由于已经将点拆过了,所以不加权)最小。显然,是在所有点的中位数(每一个点开成val个)的位置距离和最小。这样的话我们二分,对于每一个二分过程中的中间点check一下即可。
最后,附上丑陋的代码... ...
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
int n,m,a[100005];
ll tot,sum[100005];
bool check(int x)
{
int j,mid,pos;
for(int i=1;i+x-1<=n;i++)
{
j=i+x-1;
mid=i+(x>>1)-1;
pos=j-(x>>1)+1;
if(sum[j]-sum[pos-1]-sum[mid]+sum[i-1]<=tot)
return true;
}
return false;
}
int main()
{
scanf("%d%d%lld",&n,&m,&tot);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
int l=0,r=n;
while(l+1<r)
{
int mid=(l+r)>>1;
if(check(mid))
l=mid;
else r=mid-1;
}
if(check(r)) printf("%d\n",r);
else printf("%d\n",l);
return 0;
}
小结:对于加权的问题,我们可以将它拆掉,看成不加权的问题。