排队(PD.cpp)
[问题描述]
Nc参加完比赛之后,实在是太累了,就直接倒在床上睡了过去,慢慢的他就进入了梦乡。Nc梦到他变成了一名军人,他正在给一些刚入伍的军人进行军训,这些军人分别站在N个点上,每个点坐标为Pi, 一个点上有ci个军人,,这样显的非常不好看,Nc很不爽,他想让队伍展开,但是只能站成一排,每个人之间的距离不能小于limit。假设军人的移动速度为1,那么Nc想知道最快多久使队伍符合他的要求.
[输入文件]
第一行一个整数T ,输入包含T组数据.
接下来T组数据,第一行 两个整数n,limit,接下来n行 每行两个整数pi,ci. 输入保证pi单调递增.
[输出文件]
对于每组数据 输出Case #k: ans. 代表满足Nc要求的最小时间(保留6位小数). K表示是第几组测试数据. 冒号后面有空格.
[输入样例]
2
3 2
0 1
3 2
6 1
2 2
0 3
1 1
[输出样例]
Case #1: 1.000000
Case #2: 2.500000
[数据范围和约定]
对于30% 的数据, n<=20; limit<=5;
对于100% 的数据,n<=200; limit<=10^6; 0 <= | pi |<=100000 ; ci的和不超过10^6; T<=50;
[分析]
这个题目显然就是二分。每次将一个点上的所有士兵所能够移动到的最左边区间计算出来,若不能满足某个点,那么就不成立,反之则成立。
#include <iostream>
#include <cstdio>
using namespace std;
long long t,n,limit;
double ans,l,r;
long long d[2000][3];
inline double Max(double a,double b){
return a>b?a:b;
}
void init(){
scanf("%I64d%I64d",&n,&limit);
for(long long i=1;i<=n;i++)scanf("%I64d%I64d",&d[i][1],&d[i][2]);
}
bool pan(double s){
double cnt=-44073709550016000000000015.0;
for(long long i=1;i<=n;i++){
double ss=d[i][1]-s,ts=d[i][1]+s;
ss=Max(ss,cnt);
if(ts<cnt)return false;
if((d[i][2]-1)*limit>(ts-ss)){return false;}
cnt=(((d[i][2]-1)*limit)+ss)+limit;
}
return true;
}
void work(long long step){
l=0;r=44073709550000160000000015.0;
ans=44073709550016000000000015.0;
while(r-l>=1e-10){
double mid=(r+l)/2;
bool flag=pan(mid);
if(flag){
if(ans>mid)ans=mid;
if(r==mid)break;
r=mid;
}
else{
if(l==mid)break;
l=mid;
}
}
printf("Case #%I64d: %.6lf\n",step,ans);
}
int main(){
freopen("pd.in","r",stdin);
freopen("pd.out","w",stdout);
scanf("%I64d",&t);
for(long long i=1;i<=t;i++){
init();
work(i);
}
return 0;
}