【usaco2013 mar】lazy_bronze
题目描述
夏天又到了,奶牛贝里斯开始变得非常懒惰。他想要站在一个地方,然后只走很少的一段路,就能吃到尽可能多的美味的青草。有N块草坪排列在一条直线上,第i个草坪拥有g_i数量的青草,第i个草坪所在的位置是x_i。奶牛贝里斯想要在直线上选择一个点作为他的初始点(初始点有可能和草坪的位置重合),这样他就能吃到以这个点为中点距离不超过K的位置上的所有青草。如果初始点可以自由选择的话,请帮助贝里斯计算他最多能吃到的青草的数量。
输入
第一行是两个正整数,表示N和K。
第2行到第N+1行,每行两个整数,第i行的两个整数表示第i个草坪的g_i和x_i。
输出
输出贝里斯最多能吃到的青草数量。
样例输入
4 3
4 7
10 15
2 2
5 1
样例输出
11
数据范围限制
1<=N<=100000,1<=g_i<=10000,0<=x_i<=1000000,1<=k<=2000000。
提示
如果贝里斯将初始点选择在x=4的位置,那么他可以吃到x=1,x=2和x=7这三个地方的青草,总共是11。
题目大意
输入n组数,给出每一组数的位置x[i]和每组数的数值g[i]。求从任意某点开始不出k能收集到的最大的数值。
题目解析(两种解法)
1.(暴力)我们为了节省时间复杂度,可以开一个前缀和数组pre[i]。然后开始枚举每一个点前面2k范围以内可以收集到的数(所以下面的循环是倒着来的),然后直接暴力做出最大值就好了。(我这个程序还是90分……但大家也是可以学思路的)
这里说一下这个前缀和求一段值,我们可以这样求pre[i]-pre[i-k*2-1],重点:要-1。
#include<cstdio>
using namespace std;
long long n,k,g[100005],x[100005],f[1000005],m=1000005,pre[1000005],ans=-1;
long long max(long long a,long long b)
{
if(a>b) return a;
else return b;
}
void putin()
{
scanf("%lld%lld",&n,&k);
for(long long i=1;i<=n;++i)
{
scanf("%lld%lld",&g[i],&x[i]);
f[x[i]]=g[i];
}
for(long long i=1;i<=m;++i)
pre[i]=pre[i-1]+f[i];
}
int main()
{
freopen("lazy_bronze.in","r",stdin);
freopen("lazy_bronze.out","w",stdout);
putin();
for(long long i=m;i>=k*2+1;--i)
ans=max(ans,pre[i]-pre[i-k*2-1]);
printf("%lld",ans);
return 0;
}
2.(贪心,求学老曾zhy_Learn的思路程序都是他的)求最大值,那贪心是可以考虑的一种方法。我们可以将输入的数据快排跑一遍,这样无疑会大大减少后续的时间。
#include<bits/stdc++.h>
using namespace std;
struct node{
int g,v;
}a[100005];
bool cmp(node x,node y){
return x.v<y.v;
}
int n,k,l,r,ma,ans,u=1;
int main(){
freopen("lazy_bronze.in","r",stdin);
freopen("lazy_bronze.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i].g,&a[i].v);
}
sort(a+1,a+1+n,cmp);
l=a[1].v;
for(int i=1;i<=n;i++){
r=a[i].v;
ma+=a[i].g;
if(r-k*2>l){
ans=max(ma-a[i].g,ans);
while(r-k*2>l){
ma-=a[u].g;
u++;
l=a[u].v;
}
}
}
ans=max(ma,ans);
printf("%d",ans);
fclose(stdin);
fclose(stdout);
return 0;
}//by zhy_Learn
这两种解法中,第一种会比第二种要快一点的,毕竟第二种没有用到前缀和优化。在这里,谢谢老曾的指导!好了,那这道题就这么完成了。