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
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
HINT
1 ≤ R ≤ 100,000
1 ≤ L ≤ 1,000,000,000
0 ≤ B ≤ 2,000,000,000,000,000
正解:二分答案。
$IOI$第一题,还是道水题。。
考虑二分答案,二分到$mid$时分奇偶讨论一下$mid$个点的中点到这些点的距离,复杂度为$O(mid)$然后我们从前往后推,发现推到下一个中点时只需改变左右两个端点到中点的距离就行了,所以改变中点的复杂度是$O(1)$的,那么每次$check$的复杂度就是$O(n)$的。于是我们就可以在$O(nlogn)$的时间内解决这个问题了。
1 //It is made by wfj_2048~ 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 #include <cstdlib> 6 #include <cstdio> 7 #include <vector> 8 #include <cmath> 9 #include <queue> 10 #include <stack> 11 #include <map> 12 #include <set> 13 #define inf (1<<30) 14 #define N (500010) 15 #define il inline 16 #define RG register 17 #define ll long long 18 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 19 20 using namespace std; 21 22 ll a[N],n,l,b,ans; 23 24 il ll gi(){ 25 RG ll x=0,q=1; RG char ch=getchar(); 26 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 27 if (ch=='-') q=-1,ch=getchar(); 28 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 29 return q*x; 30 } 31 32 il ll check(RG ll key){ 33 RG double tot=0; 34 if (key&1){ 35 RG ll len=key>>1,p=len+1; 36 for (RG ll i=1;i<=key;++i) tot+=abs(a[p]-a[i]); 37 if (tot<=b) return 1; 38 for (++p;p+len<=n;++p){ 39 tot-=abs(a[p-1]-a[p-len-1]); 40 tot+=abs(a[p]-a[p+len]); 41 if (tot<=b) return 1; 42 } 43 } else{ 44 RG ll len=key>>1,p=len; 45 for (RG ll i=1;i<=key;++i) tot+=abs(a[p]-a[i]); 46 if (tot<=b) return 1; 47 for (++p;p+len<=n;++p){ 48 tot-=abs(a[p]-a[p-len]); 49 tot+=abs(a[p]-a[p+len]); 50 if (tot<=b) return 1; 51 } 52 } 53 return 0; 54 } 55 56 il void work(){ 57 n=gi(),l=gi(),b=gi(); 58 for (RG ll i=1;i<=n;++i) a[i]=gi(); 59 RG ll l=0,r=n,mid; 60 while (l<=r){ 61 mid=(l+r)>>1; 62 if (check(mid)) ans=mid,l=mid+1; 63 else r=mid-1; 64 } 65 printf("%lld\n",ans); return; 66 } 67 68 int main(){ 69 File("ricehub"); 70 work(); 71 return 0; 72 }