题意:青蛙从0到m,每次跳的距离不大于L,可以在任意位置添加任意数量的石头,青蛙会自动选择跳跃次数最少的方案,求青蛙可能的最大的跳跃次数。
链接:http://acm.hdu.edu.cn/showproblem.php?pid=5037
思路:模拟+贪心。将每次青蛙跳跃的过程模拟,在跳跃过程中贪心选择出相同跳跃次数情况下距离最短的情况。若该处没有石子就加石子。
注意点:直接模拟可能因为跳跃次数过多而TLE,因此当两块石头过远的时候,可以一次处理完这两块石头间的所有过程。跳跃次数为 len/(L+1)。
AC代码如下:
Run ID | Submit Time | Judge Status | Pro.ID | Exe.Time | Exe.Memory | Code Len. | Language | Author |
11702634 | 2014-09-22 18:30:53 | Accepted | 5037 | 812MS | 1080K | 2131 B | G++ | luminous11 |
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int ncase;
int len[200005];
int m, n, l;
int dis = 0;
int cnt = 0;
int k = 1;
int tmp = 0;
void init ()
{
cnt = 0;
k = 1;
dis = 0;
tmp = -10000000;
memset ( len, 0, sizeof ( len ) );
len[0] = 0;
}
int solve( )
{
int ans = 0;
int i = 0;
while ( dis < m )
{
//cout << "dis = " << dis << endl;
while ( len[i] <= l + dis && i <= n )
{
i ++;
}
if ( i > n )
{
return ans + 1;
}
if ( len[i - 1] > dis )
{
tmp = dis;
dis = len[i - 1];
ans ++;
}
else
{
k = ( len[i] - dis ) / ( l + 1 ) - 1;
if ( k > 0 )
{
tmp = max( dis + 1, tmp + l + 1 ) + ( k - 1 ) * ( l + 1 );
dis += k * ( l + 1 );
ans += k * 2;
}
else
{
k = dis;
dis = max ( dis + 1, tmp + l + 1 );
tmp = k;
ans ++;
}
}
//cout << ans << endl;
}
return ans;
}
int main()
{
//ios::sync_with_stdio( false );
scanf ( "%d", &ncase );
for ( int t = 1; t <= ncase; t ++ )
{
init();
scanf( "%d%d%d", &n, &m, &l );
for ( int i = 1; i <= n; i ++ )
{
scanf ( "%d", &len[i] );
}
len[++n] = m;
sort( len + 1, len + n );
/* for ( int i = 0; i <= n; i ++ )
{
cout << len[i] << ' ';
}
cout << endl;*/
cnt = solve ( );
printf( "Case #%d: %d\n", t, cnt );
}
return 0;
}