BZOJ2600: [Ioi2011]ricehub解题报告

题目链接

解题思路

注意到原题中有“至多花费B元可得到的最多稻米数”,故这题可以用二分答案法做。
但我们注意到这题二分稻米数并不好做。
这里介绍一种two-points的方法。我们注意到 x i x_i xi是递增的。在递增的序列中维护一个区间可以采用two-points法.
l l l指向区间的左端点,而 r r r指向区间的右端点。我们可以发现若区间 [ l , r + 1 ] [l,r+1] [l,r+1]满足花费 ≤ B \leq B B,则区间 [ l , r ] [l,r] [l,r]的花费也会 ≤ B \leq B B。我们只要向右移动右指针 r r r,直到 [ l , r + 1 ] [l,r+1] [l,r+1]无法满足条件时,记录下 [ l , r ] [l,r] [l,r]的值。接着,移动左端点 l l l,判断新的区间 [ l + 1 , r ] [l+1,r] [l+1,r]是否满足条件,然后再移动 r r r……这样的时间复杂度为 O ( n ) O(n) O(n)。有兴趣的可以去搜索two-points。
接着就是如何算出区间 [ l , r ] [l,r] [l,r]内的米仓的花费。我们只要判断运载这个区间内的稻米到达米仓的花费 w w w的最小值是否 ≤ B \leq B B即可。
w = ∑ i = l r ∣ x [ i ] − k ∣ w=\sum_{i=l}^r|x[i]-k| w=i=lrx[i]k k k k为选定的米仓的坐标值。易得当 k k k等于 x [ l + r 2 ] x[\frac{l+r}{2}] x[2l+r]时, w w w最小。
问题就是怎么计算 w m i n = ∑ i = l r ∣ x [ i ] − x [ l + r 2 ] ∣ w_{min}=\sum_{i=l}^r|x[i]-x[\frac{l+r}{2}]| wmin=i=lrx[i]x[2l+r]了。
m = ⌊ l + r 2 ⌋ m= \left \lfloor \frac{l+r}{2} \right \rfloor m=2l+r
w m i n = ∑ i = l r ∣ x [ i ] − x [ m ] ∣ w_{min}=\sum_{i=l}^r|x[i]-x[m]| wmin=i=lrx[i]x[m] = ∑ i = m + 1 r ( x [ i ] − x [ m ] ) + ∑ j = l m − 1 ( x [ m ] − x [ j ] ) =\sum_{i=m+1}^r(x[i]-x[m])+\sum_{j=l}^{m-1}(x[m]-x[j]) =i=m+1r(x[i]x[m])+j=lm1(x[m]x[j]) = ∑ i = m + 1 r x [ i ] − ( r − m ) ∗ x [ m ] + ( m − l ) ∗ x [ m ] − ∑ j = l m − 1 x [ j ] =\sum_{i=m+1}^rx[i]-(r-m)*x[m]+(m-l)*x[m]-\sum_{j=l}^{m-1}x[j] =i=m+1rx[i](rm)x[m]+(ml)x[m]j=lm1x[j]
s u m [ i ] 表 示 x [ i ] 的 前 缀 和 sum[i]表示x[i]的前缀和 sum[i]x[i]
原 式 = ( s u m [ r ] − s u m [ m ] ) − ( r − m ) ∗ x [ m ] 原式=(sum[r]-sum[m])-(r-m)*x[m] =(sum[r]sum[m])(rm)x[m] + ( m − l ) ∗ x [ m ] − ( s u m [ m − 1 ] − s u m [ l − 1 ] ) +(m-l)*x[m]-(sum[m-1] -sum[l-1]) +(ml)x[m](sum[m1]sum[l1])
O ( 1 ) O(1) O(1)内算出 w m i n w_{min} wmin,nice!

详细代码

#define rg register
#define il inline
#define DEBUG printf("[Passing [%s] in line %d.]\n", __func__, __LINE__)
#define putline putchar('\n')
#define putsp putchar(' ')
#define Rep(a, s, t) for(rg int a = s; a <= t; a++)
#define Repdown(a, t, s) for(rg int a = t; a >= s; a--)
typedef long long ll;
#include<cstdio>
#define rs freopen("test.in", "r", stdin), freopen("test.out", "w", stdout)
struct IO
{
	IO(int set = 0) {if(set) rs;} 
	template<typename T> il IO r(T& x)const
	{
	    x = 0; T f = 1; char ch = getchar();
	    for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
	    for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + int(ch - '0');
	    x *= f; return *this;
	}
	template<typename T> il IO w(T x)const
	{
	    if(x < 0) {putchar('-'); x = -x;}
	    if(x >= 10) w(x / 10);
	    putchar(x % 10 + '0'); return *this;
	}
	template<typename T> il IO wl(const T& x)const {w(x), putline; return *this;}
	template<typename T> il IO ws(const T& x)const {w(x), putsp; return *this;}
	il IO l() {putline; return *this;}
	il IO s() {putline; return *this;}
}io;
template<typename T> il T Max(const T& x, const T& y) {return y < x ? x : y;}
template<typename T> il T Min(const T& x, const T& y) {return y < x ? y : x;}
template<typename T> il void Swap(T& x, T& y) {T tmp = x; x = y; y = tmp;}

int N, L;
ll B;
ll x[100005];
ll sum[100005];
int ans;

bool check(int l, int r)
{
	int mid = (l + r) >> 1;
	ll sum1 = sum[r] - sum[mid] - (r - mid) * x[mid];
	ll sum2 = (mid - l) * x[mid] - (sum[mid - 1] - sum[l - 1]);
	return sum1 + sum2 <= B;
}
int main()
{
    //FileReset();
	io.r(N).r(L).r(B);
	for(rg int i = 1; i <= N; i++) io.r(x[i]), sum[i] = sum[i - 1] + x[i];
	int r = 1;
	for(rg int l = 1; l < N; l++)
	{
		while(r < N && check(l, r + 1)) r++;
		ans = Max(ans, r - l + 1);
	}
	io.wl(ans);
    return 0;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

日居月诸Rijuyuezhu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值