【传送门】
http://codeforces.com/contest/579/problem/C
【题意】
给你一段波浪线,点数变化情况是——
(0,0)->(x,x)->(2x,0)->(3x,x)
也就是,先以1的斜率递增长度x,再以-1的斜率递减长度x,
再给你一个点(a,b),让你输出尽可能小的x,使得(a,b)在这样的折线上。
【类型】
贪心+讨论
【分析】
首先x>=b是一定的,
然后为了方便,我们把(a,b)映射到x轴上
我们不知道(a,b)是在上升段还是下降段,
所以映射有两种——
(1)a-=b;
(2)a+=b;
然后a就是横坐标了
而不管a是-=b还是+=b,现在的a肯定都将是2x的整数倍,我们是希望使得x尽可能小,也就是这个倍数尽可能大。
然而这里有一个限定条件,x>=b
所以我们假定x=b,这种情况下x最小,倍数也会尽可能大。
于是我们求出这个倍数(因为要求是整数),然后再求出其对应的x,并更新答案。
【时间复杂度&&优化】
O(1)
这题的标程,代码只有2行——
if(a<b)puts("-1");
else printf("%.12f\n",(a+b)/(2.*((a+b)/(2*b))));
咦,其实和我之前写的代码一样,但是简化了,不用再考虑a-b
为什么呢?
因为可以总结为——
一定是把这个点向最右端映射才最优。
为什么呢?
首先不论向左还是向右映射,都是恰好要求是2kx的位置,
然后x是有最小值的,所以我们能求得k的最大值,并且向下取整得到最大可能的整数k。
然后答案的映射是
k1=[(a-b)/(2b)]
k2=[(a+b)/(2b)]
v1=(a-b)/k1
v2=(a+b)/k2
k2一定比k1大1
而且k2/k1 >= (a+b)/(a-b) (分母与分子差固定,分母与分子越接近数值就越大)
于是在(a-b)/k1与(a+b)/(k1+1)的大小比较的时候
必然有(a-b)/k1 >= (a+b)/k2
取(a+b)/k2即可,于是就有了2行代码的标程
【trick】
然而这道题有一个点比较特殊,就是——
我们算出倍数k之后,有if(k)gmin(ans,lft/(2.0*k));
因为涉及到除法,所以这里k必须要求是整数。
然而k是可能为0而且合法的,这种情况出现在a=b的时候,有的写法会在这里卡住,特判一下即可
【数据】
Input
3 1
Output
1.000000000000
Input
1 3
Output
-1
Input
4 1
Output
1.250000000000
【代码】
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<functional>
#include<string>
#include<algorithm>
#include<time.h>
#include<bitset>
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T> inline void gmax(T &a,T b){if(b>a)a=b;}
template <class T> inline void gmin(T &a,T b){if(b<a)a=b;}
using namespace std;
const int N=0,M=0,Z=1e9+7,maxint=2147483647,ms31=522133279,ms63=1061109567,ms127=2139062143;const double eps=1e-8,PI=acos(-1.0);//.0
int a,b;
int main()
{
while(~scanf("%d%d",&a,&b))
{
int x=a+b;
int k=x/(b<<1);
if(k)printf("%.12f\n",x/(2.0*k));
else printf("-1\n");
}
return 0;
}