1. 程式人生 > >【ZOJ4062】Plants vs. Zombies(二分)

【ZOJ4062】Plants vs. Zombies(二分)

題意:有n個植物排成一排,標號為1-n,每株植物有自己的生長速度ai,每對植物澆一次水,該株植物就長高ai,

現在機器人從第0個格子出發,每次走一步,不能停留,每一步澆一次水,總共可以走m步,問最矮的植物最高是多少。

n<=1e6,sigma n<=1e7,0<=m<=1e12,1<=a[i]<=1e5

思路:7Y……你不死誰死

顯然最小值最大可以二分,二分答案,最優的策略一定是從左到右依次左右橫跳,直到當前格子不小於二分的值

一個致命的細節:最後一個如果在倒數第二個左右橫跳的時候已經夠了則不需要再走到了

 1 #include<cstdio>
 2
#include<cstring> 3 #include<string> 4 #include<cmath> 5 #include<iostream> 6 #include<algorithm> 7 #include<map> 8 #include<set> 9 #include<queue> 10 #include<vector> 11 using namespace std; 12 typedef long long ll; 13 typedef unsigned int
uint; 14 typedef unsigned long long ull; 15 typedef pair<int,int> PII; 16 typedef vector<int> VI; 17 #define fi first 18 #define se second 19 #define MP make_pair 20 #define N 110000 21 #define M 51 22 #define MOD 1000000007 23 #define eps 1e-8 24 #define pi acos(-1) 25 #define oo 1010000000 26
27 ll a[N],b[N],m; 28 int n; 29 30 int isok(ll k) 31 { 32 for(int i=1;i<=n+1;i++) b[i]=0; 33 ll t=0; 34 for(int i=1;i<=n;i++) 35 { 36 if(i==n&&b[n]>=k) continue; 37 t++; 38 if(t>m) return 0; 39 b[i]+=a[i]; 40 if(b[i]<k) 41 { 42 ll tmp=(k-b[i])/a[i]; 43 if(tmp*a[i]+b[i]<k) tmp++; 44 t=t+tmp*2; 45 if(t>m) return 0; 46 b[i]+=a[i]*tmp; 47 b[i+1]+=a[i+1]*tmp; 48 } 49 } 50 if(t>m) return 0; 51 return 1; 52 } 53 54 int main() 55 { 56 int cas; 57 scanf("%d",&cas); 58 for(int v=1;v<=cas;v++) 59 { 60 scanf("%d%lld",&n,&m); 61 for(int i=1;i<=n;i++) scanf("%lld",&a[i]); 62 ll l=1; 63 ll r=1e17; 64 ll last=0; 65 while(l<=r) 66 { 67 ll mid=(l+r)/2; 68 if(isok(mid)){last=mid; l=mid+1;} 69 else r=mid-1; 70 } 71 printf("%lld\n",last); 72 } 73 return 0; 74 } 75