本题链接
本题 大意就是 给你一个数组 ,大小表示 花的高度 输入告诉你 花的个数,浇几天花(一天长一个单位)和浇花能覆盖花的个数,问你 浇完后高度最小值的最大情形。
虽然最近 刚学了二分 自认为 还是了解比较清楚,但是做这题开始没看出来是二分,惭愧。。。。
这题就是明显二分,在0~1e10范围内二分,看能满足这个题意的值。有个细节要注意,在模拟浇花那一个范围內花都会被 浇的时候,开始就想直接一个for(),将 存差值的b[i]数组依次减就好,多好理解啊,妈蛋 结果在cf的第20个测试数据TLE了,(cf真的很棒可以看后台测试数据和别人的代码)想想 也对 ,两个for,O(n^2)肯定超时啊,后来看了别人的题解,知道这里有一个 O(n)的解决办法,就是多一个数组c[i]存每次到哪里就不浇花,开始让x,存每次减去要交几次水的个数,再让x+c[i],就是这个点到底有没有被前面教的水覆盖到。
先上 原来明了但是TLE的代码
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
long long a[210000],b[210000];
int main()
{
long long n,m,w;
scanf("%I64d %I64d %I64d",&n,&m,&w);
for(long long i=1;i<=n;i++)
scanf("%I64d",&a[i]);
long long low=0,mid,top=1e10,ans=-1;
while(low<=top)
{
mid=(low+top)/2;
memset(b,0,sizeof(b));
for(long long i=1;i<=n;i++)
{
b[i]=max(mid-a[i],(long long)0);
}
long long d=m;
for(long long i=1;i<=n;i++)
{
if(b[i]>0)
{
d-=b[i];
if(d<0)
break;
long long c=b[i];
for(long long j=i;j<i+w;j++)
{
b[j]-=c;
}
b[i]=0;
}
}
if(d<0)
{
top=mid-1;
}
else
{
ans=mid;
low=mid+1;
}
}
printf("%I64d\n",ans);
return 0;
}
下面 是优化了浇水时覆盖一片花的AC代码
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
long long a[100010],b[100010],c[100010];//c是用来实现,浇水时一朵花覆盖到其他几朵的功能,具体实现看后面。
int main()
{
long long n,m,w;
scanf("%I64d %I64d %I64d",&n,&m,&w);
for(long long i=1;i<=n;i++)
scanf("%I64d",&a[i]);
long long low=0,mid,top=1e10,ans=-1;
while(low<=top)/=要有
{
mid=(low+top)/2;
for(long long i=1;i<=n;i++)
{
b[i]=max(mid-a[i],(long long)0);
}
memset(c,0,sizeof(c));
long long d=m,x=0;
for(long long i=1;i<=n;i++)
{
x+=c[i];//判断这个点有没有被前面教的水覆盖到
b[i]-=x;/处理之后的b[i]才是这个点面对前面教其他花后,自己有没有被浇到后的差值
if(b[i]>0)
{
d-=b[i];
if(d<0)
break;
x+=b[i];
c[i+w]-=b[i];
b[i]=0;
}
}
if(d<0)
{
top=mid-1;
}
else
{
ans=mid;//存每一次中间值
low=mid+1;
}
}
printf("%I64d\n",ans);
return 0;
}
写完这题,感觉贪心的思想几乎没有,还是考对二分的理解