传说中2004年亚洲赛伊朗德黑兰赛区的B题,也是当时比较水的题目,做这道题目用了我2天去想公式,真的是很痛苦的事情,好了,在自己痛苦了几天之后,把代码给贴上吧,都做了详细的注释,是用二分枚举+贪心判定实现的...可我还是不能保证以后碰到后会不会做出来,郁闷的题目.

Code
#include <iostream>
using namespace std;
bool hash[30010];
long lmax;
bool check( long x )
{
long i , j , b;
b = 0;
//i为能上的最高层楼
//b为电梯停的次数
i = x/20 + 2;
//时间全用做步行,正好不能上的楼层
while( i <= lmax )//如果最高层比最高代价能上的层数要高
{
while( i <= lmax && !hash[i] )i++;
//i没人就不理它
if((i - 1)*4 + 10*b > x ) return false;
//如果坐电梯都上不到i层 那就死吧
j = ( x - 10*b + 20*i +4 )/24;
//j=(x-10*b-4*(i-1))/24+i;
// x-10*b-4*(i-1)是剩余的时间
//24可以看做电梯上 人下的总速度
//j表示要达到i层的人,在j层停照样照样走路走得到,i以下的人从前一次停的地点往上走,i到j之间的人从J往下走
//电梯不回头 人回头
//此时(j)层为停的最适合楼层
i = ( x - 10*b + 16*j + 4)/20 + 1;//剩下的时间能爬的最高层
//i=(x-10*b-(j-1)*4)/20+j+1
//x总消耗的时间-坐电梯消耗的时间10*b-上电梯所消耗的时间
//这些时间用来步行能上的层数+j层停下的位置+1为最大可上的楼层
b++;//电梯能停的次数+1
}
//否则通过检验 因为最高代价下都能上到最高层
return true;
}
int main()
{
long n;
while (scanf("%ld",&n)!=EOF&&n)
{
memset(hash,0,sizeof(hash));
long i;
lmax=0;
for (i=0;i<n;++i)
{
long floor;
scanf("%ld",&floor);
hash[floor]=true;
if (floor>lmax)
{
lmax=floor;
}
}
long low=20*0,high=14*(lmax+1);
while (low<high)
{
long mid=(low+high)/2;
if (check(mid))
{
high=mid;
}
else
{
low=mid+1;
}
}
printf("%ld\n",low);
}
return 0;
}