这题如果用普通的暴力不加优化分分钟超时,因为是10^9,最坏情况会超过10^7计算量,
超时代码:
//K - Frog
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define MAXN 200000
typedef long long LL;
LL R[MAXN];//存放初始化即有的石头的位置
int main()
{
int i,j;
LL N,M,L;
int kase,casenum;
int ans;
LL pre;
LL pos;
scanf("%d",&casenum);
kase=0;
while(casenum--)
{
scanf("%lld%lld%lld",&N,&M,&L);
memset(R,0,sizeof(R));
for(i=1;i<=N;i++)
scanf("%lld",&R[i]);
sort(R+1,R+1+N);
ans=pos=pre=0;
i=1;
while(pos<M)
{
for(;i<=N;i++)
if(R[i]<=pos+L&&R[i+1]>pos+L)
break;
if(i==N+1)//如果i>N有可能是所有石头都在跳跃范围内
{
pos=R[i-1];
ans++;
if(pos+L>=M)
{
ans++;
break;
}
i++;//因为在这种情况下下一轮跳跃就应该是人工加石头了
}
else
{
if(i>N+1)//初始化的石头已经跳完了
{
while(pos<M)
{
ans++;
pos++;
if(pos+L>=M)
{
pos=M;
ans++;
break;
}
}
}
else//还剩余了初始化的石头
{
if(i==pre)//接下来他一块石头也够不着
{
i++;
for(j=R[i];j>=1;j--)
{
if(pos+L+j<R[i]&&pos+L+j+1>=R[i])
{
pos=R[i];
i++;
ans+=j;
break;
}
}
}
else//有石头可以落脚
{
pos=R[i];
i++;
a//K - Frog
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define MAXN 200000
typedef long long LL;
LL R[MAXN];//存放初始化即有的石头的位置
int main()
{
int i,j;
LL N,M,L;
int kase,casenum;
int ans;
LL pre;
LL pos;
scanf("%d",&casenum);
kase=0;
while(casenum--)
{
scanf("%lld%lld%lld",&N,&M,&L);
memset(R,0,sizeof(R));
for(i=1;i<=N;i++)
scanf("%lld",&R[i]);
sort(R+1,R+1+N);
ans=pos=pre=0;
i=1;
while(pos<M)
{
for(;i<=N;i++)
if(R[i]<=pos+L&&R[i+1]>pos+L)
break;
if(i==N+1)//如果i>N有可能是所有石头都在跳跃范围内
{
pos=R[i-1];
ans++;
if(pos+L>=M)
{
ans++;
break;
}
i++;//因为在这种情况下下一轮跳跃就应该是人工加石头了
}
else
{
if(i>N+1)//初始化的石头已经跳完了
{
while(pos<M)
{
ans++;
pos++;
if(pos+L>=M)
{
pos=M;
ans++;
break;
}
}
}
else//还剩余了初始化的石头
{
if(i==pre)//接下来他一块石头也够不着
{
i++;
for(j=R[i];j>=1;j--)
{
if(pos+L+j<R[i]&&pos+L+j+1>=R[i])
{
pos=R[i];
i++;
ans+=j;
break;
}
}
}
else//有石头可以落脚
{
pos=R[i];
i++;
ans++;
}
}
}
}
printf("Case #%d: %d\n",++kase,ans);
}
return 0;
}
ns++;
}
}
}
}
printf("Case #%d: %d\n",++kase,ans);
}
return 0;
}
这题还是蛮难的,网上普遍流行两种做法。
(1)参考博客:
https://www.cnblogs.com/yuiffy/p/3984846.html
https://blog.csdn.net/weilehuozhe/article/details/48300165
https://www.cnblogs.com/yuiffy/p/3984846.html
这种方法其实是算一种模拟过程,然而并没有看懂代码。。。。
(2)我用的是第二种方法,参考博客:
https://blog.csdn.net/u014569598/article/details/39471913#commentsedit
https://blog.csdn.net/Irving0323/article/details/81781026
确实有点难理解,
其实就拿0, 5, 8,其中L=3这组数据开涮,可以发现第一次默认是跳到了第一块石头上(先不管到底有没有通过sum+x>=L+1来判断是否再加一个1),意思是每次跳跃都默认跳到下一块石头上,而不管中间的距离是多少,也不管在哪里加石头,至于中间调不到的距离就用数学计算强制给他加上
所以说这是一种非模拟,纯计算的手段,但是分析起来好像没有那么复杂。
这里我有几个问题:
(1)
我的理解是,当sum的初值设为L时其实就已经避免了这种情况,以我上述的数据为例,当跳到5的时候,本来模拟过程应该是两步的,因为余数之和还没有>+L+1,但是在这一步程序走出来是3,所以是强制加一,所以这种问题可以避免。
但这样就又牵扯出来一个问题:但是如果最后一步的时候余数之和又大于L+1了答案就多了一?
其实是不会的,用我上述那个例子试出来是刚刚好。。。。(原因不详)
这种题一般要排序,题目很坑的。
还有,将起点和终点都加入R数组里面,是一个良好的习惯,就不用特意判断终点了。
核心代码:
代码:
//K - Frog
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define MAXN 200010
typedef long long LL;
int R[MAXN];//存放石头的初始位置
int main()
{
int i;
int N,M,L;
int casenum,kase;
int ans;
int sum;//记录前几次的余数的和
int x,y;
scanf("%d",&casenum);
kase=0;
while(casenum--)
{
scanf("%d%d%d",&N,&M,&L);
memset(R,0,sizeof(R));
for(i=1;i<=N;i++)
scanf("%d",&R[i]);
R[0]=0;
R[N+1]=M;
sort(R,R+N+1);
sum=L;
ans=0;
for(i=1;i<=N+1;i++)
{
x=(R[i]-R[i-1])%(L+1);
y=(R[i]-R[i-1])/(L+1);
if(sum+x>=L+1)
{
ans++;
sum=x;
}
else
sum+=x;
ans+=2*y;
}
printf("Case #%d: %d\n",++kase,ans);
}
return 0;
}