2018年ACM-ICPC亚洲青岛区域竞赛 - E - Plants vs. Zombies

Whiteying

2018-11-14 00:00:50

Personal

# A类 借鉴与:https://blog.csdn.net/BePosit/article/details/83929892 # 题目链接: https://vjudge.net/problem/ZOJ-4062 # 题意: 看到题目以为是个非常复杂的题。 但显然题意和植物大战僵尸没有半毛钱关系(出题人过来我保证不打死你(╯‵□′)╯︵┻━┻) ## (真)题意(雾 你的房子在n点每个点都有一颗高度为0的花,浇一次水花会长a[i]。 你有一个机器人,刚开始在你家,最多走m步,每一步只能往前走或者往后走,每走到一个地方除了房子都会给花浇水,问m步以后最低那朵花的高度最大是多少。 # 思路: 最大化最小值,用二分的思想 从前往后计算每一朵花要满足答案需要浇多少次水。 ------------ 二分条件:left<right 二分计算:middle=(left+right+1)/2 二分转移:符合条件时left=middle,不符合条件时 right=middle-1 ------------ 对于一朵花达不到我们所需要的高度时,跟它右边那朵花那个反复跳即可。这样的话每一次二分判断,先预处理出实际应该遍历这个点几次 到达一个点时先sum++,因为第一次总是要从前面过来的,不是在后面循环过程中凑出来的 每次都是向右循环凑次数: ### sum+=(b[i]-1)*2 所以每一次需要走的次数应当减去上次循环过程中已经走过的 ### b[i+1]-=(b[i]-1); 然后记录需要使用跳多少次即可。最后只需判断次数是否大于m即可 如果到了最后需要判断是否需要sum++  ### if(i==n&&b[i]<1)break; # AC代码: ```cpp #include<iostream> #include<algorithm> #include<cstdio> #include<cstdlib> long long t,n,m; long long maxx; long long a[100005]; long long b[100005]; bool check(long long now) { long long sum=0; for(int i=1;i<=n;i++) { if(now%a[i]) b[i]=now/a[i]+1; else b[i]=now/a[i]; } for(int i=1;i<=n;i++) { if(i==n&&b[i]<1) return true; sum++; if(b[i]>1) { sum+=(b[i]-1)*2; b[i+1]-=(b[i]-1); } if(sum>m) return false; } return true; } int main() { scanf("%lld",&t); while(t--) { scanf("%lld%lld",&n,&m); maxx=0; for (int i=1;i<=n;i++) { scanf("%lld",&a[i]); if(a[i]>maxx) maxx=a[i]; } maxx=maxx*m; long long left=0,right=maxx,middle; while(left<right) { middle=(left+right+1)/2; if(check(middle)) left=middle; else right=middle-1; } printf("%lld\n",right); } return 0; } ```