题目链接:https://zoj.pintia.cn/problem-sets/91827364500/problems/91827370312
题意:你家右边有n块土地,每块土地相隔1米,第一块土地离家也相隔1米,现在你的机器人从家开始去给土地浇水,机器人每移动1米就浇一次水,第i块土地每浇一次水就会增加a[i]的防御值,整体防御值是n块土地中最小的防御值,现在你的机器人只能走m米,问你走完m米后,整体防御值最大可能为多少。
思路:防御值最大化可以想到二分,最小l=0,最大r=1e17,然后对于第i块土地,那肯定机器人是在i和i+1之间来回移动,直到第i块土地达到相应的值,相应的第i+1块土地也会增加浇水次数。
#include<stdio.h> #include<iostream> #include<string.h> #include<math.h> #include<string> #include<algorithm> #include<queue> #include<map> typedef long long ll; using namespace std; ll a[200005]; ll fun(ll mid,ll n,ll m) { ll sum=0; ll ans=0; for(int i=1;i<=n;i++) { ll x=mid/a[i]; if(mid%a[i]!=0) x++; if(x<=sum)//第i已经达到了mid { sum=0; if(i<n)//当i<n时,还是要从第i-1移动到第i,当i==n时,就都已经达到mid了,就没必要移动 ans++; } else { x-=sum;//所需要的次数减去已经浇水次数 ans=ans+2*x-1;//浇完第i块所需次数 sum=x-1;//相应的给第i+1块浇了sum次 } if(ans>m)//如果ans已经大于m了,那肯定是不可以了 return 0; } if(ans>m) return 0; return 1; } int main() { int T; scanf("%d",&T); while(T--) { ll n,m; scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); ll l=0,r=100000000000000007; ll ans; while(l<=r) { ll mid=(l+r)/2; if(mid==0)//mid=0是肯定成立的,但带到fun函数里就不一定成立了 { ans=mid; l=mid+1; continue; } if(fun(mid,n,m)==1) { ans=mid; l=mid+1; } else r=mid-1; } printf("%lld ",ans); } }