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
HINT
Source
http://www.lydsy.com/JudgeOnline/problem.php?id=2600
这道题我个人的算法是二分+枚举,网上应该还有更好的算法,在这里不多说。
首先二分可以取得几个米仓的粮食。
然后check,枚举左端点,判断可行性。
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 long long f[100010],now,k,ans,a[100010],sum,n,l,b,lef,righ,mid; 5 bool check(long long x) 6 { 7 int i,l,r,mi; 8 for (i=1;i<=n-x+1;++i) 9 { 10 l=i; r=i+x-1; mi=(l+r)/2; 11 now=a[mi]; 12 sum=now*(mi-l)-(f[mi-1]-f[l-1])+(f[r]-f[mi])-now*(r-mi); 13 //cout<<x<<' '<<i<<' '<<sum<<endl; 14 if (sum<=b) return true; 15 } 16 return false; 17 } 18 int main() 19 { 20 cin>>n>>l>>b; 21 for (int i=1;i<=n;++i) cin>>a[i]; 22 f[0]=0; 23 for (int i=1;i<=n;++i) f[i]=f[i-1]+a[i]; 24 lef=0; 25 righ=n+1; 26 ans=0; 27 while (lef<=righ) 28 { 29 mid=(lef+righ)/2; 30 if (check(mid)==true) 31 { 32 lef=mid+1; 33 if (ans<mid) ans=mid; 34 } 35 else righ=mid-1; 36 } 37 cout<<ans<<endl; 38 return 0; 39 }
优化:前缀和