题意:一条宽为m的河,上面已经有n块石头在各自的位置,青蛙每次最多跳l个单位距离。你作为上帝可以增加一些石头使得青蛙能跳到对岸,不过调皮的你想让青蛙跳的次数最多。青蛙很聪明,总会在你添加石头之后选择最少的跳跃次数。问青蛙需要跳多少次。
思路:贪心。一定要巨贪才行。方法是记录当前的位置cur和上一次的位置pre,开始是pre置为-l(因为贪)。然后让青蛙跳到能跳的最远的石头。如果跳不到,只能补石头了,但是需要补得尽可能近,也就是补在pre刚好跳不到的位置(pre+l+1,因为贪),如此重复就可以了。不过还有一个问题,河可能非常宽,如果一块一块石头补,会超时。所以我们推一个公式计算出补多少,补完之后的cur和pre,具体见代码。
#include<iostream> #include<cmath> #include<queue> #include<map> #include<set> #include<vector> #include<algorithm> #include<string.h> #include<cstdio> using namespace std; int a[200010]; int main(){ int t; cin>>t; for(int cas=1;cas<=t;cas++){ int n,m,l; scanf("%d%d%d",&n,&m,&l); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } a[0]=0; a[n+1]=m; sort(a,a+n+1); int pre=-l; int cur=0; int k=0; int ans=1; while(cur+l<m){ if(a[k+1]>cur+l){ //避免超时,一次性补上多步 int x=(a[k+1]-pre-l)/(l+1); int y; pre+=x*(l+1); if(pre+l>=a[k+1])y=x-1; else y=x; cur+=y*(l+1); if(pre>cur)swap(pre,cur); ans+=(x+y); if(x==0){//至少跳一步 ans++; int tmp=cur; cur=pre+l+1; pre=tmp; } }else{ while(a[k+1]<=cur+l){ k++; } pre=cur; cur=a[k]; ans++; } } printf("Case #%d: %d\n",cas,ans); } return 0; }