Codeforces 780 H Intranet of Buses

在这里插入图片描述在这里插入图片描述毒瘤出题人A了一道毒瘤题然后搬。。。。。。
思路很简单,二分答案后two-pointers把每对边,相邻的鸽子会各自在其上的情况求距离小于二分的答案的时间区间,这是个二次函数直接求。然后发现判定答案就是找交集。转化为非法区间取并就可以排序贪心判定合法。

这题让我深刻的理解到计算几何题好像是过了样例就能A,在打完后完全不相信自己能A的蒟蒻如是说。

#include<bits/stdc++.h>
#define maxn 200005
#define eps 1e-7
using namespace std;

inline int dcmp(double a)
{
	if(fabs(a) < 1e-7) return 0;
	return a>0?1:-1;
}

int n,m,npt;
double len[maxn],arrtim[maxn];
inline double sqr(double x){ return x*x; }
struct Point
{	double x,y;
	Point(double x=0,double y=0):x(x),y(y){}
	Point operator +(const Point &B)const{ return Point(x+B.x,y+B.y); }
	Point operator -(const Point &B)const{ return Point(x-B.x,y-B.y); }
	Point operator *(const double B)const{ return Point(x*B,y*B); }
	double Len(){ return sqrt(sqr(x)+sqr(y)); }
}st,P[maxn],dir[maxn];
double dist(Point A,Point B){ return (B-A).Len(); }
double C;
double tl[maxn*10],tr[maxn*10];
int ct[maxn*10],cnt_t;
inline bool cmp(const int &u,const int &v){ return tl[u] < tl[v]; }
inline double diV(double t){ return floor(t / C);
}
inline double dmod(double t)
{
	return t - C * floor(t / C);
}

bool ERROR = 0;
void Insert(double s,double t)
{	
	if(dcmp(diV(t) - diV(s)) == 1)
	{
		if(dcmp(dmod(t) - dmod(s)) == 1 || dcmp(diV(t)-diV(s)-1) == 1) 
			ERROR = 1;
		else 
		{
			tl[++cnt_t] = dmod(s) , tr[cnt_t] = C;
			tl[++cnt_t] = 0 , tr[cnt_t] = dmod(t);
		}
	}
	else
	{
		tl[++cnt_t] = dmod(s) , tr[cnt_t] = dmod(t);
	}
}

inline bool check(double mid)
{
	//printf("%lf\n",mid);
	double tnow=0;
	cnt_t = ERROR = 0;
	Point st1 = P[1] , st2 = st;
	for(int npt1=2,npt2=npt;npt1<=n+1 && npt2 <= npt + n;)
	{
		double lim1 = arrtim[npt1] , lim2 = arrtim[npt2] - C;
	//	if(mid <=2) 
	//		printf("%d %d %lf %lf\n",npt1,npt2,lim1,lim2);
		/*
		
		(st1 + k * dir[npt1-1] - st2 - k * dir[npt2-1]).Len() <= mid
		
		((st1.x-st2.x)+k(dir[npt1-1].x-dir[npt2-1].x))^2
		+
		((st1.y-st2.y)+k(dir[npt1-1].y-dir[npt2-1].y))^2
		<= mid ^ 2
		
		*/
	//	if(mid>=1.02 && mid <= 1.04)printf("%d %d\n",npt1,npt2);
	//	if(mid >= 1.02 && mid <= 1.04)printf("%lf %lf %lf %lf\n",st1.x,st1.y,st2.x,st2.y);
		double A1 = st1.x - st2.x , A2 = dir[npt1-1].x-dir[npt2-1].x;
		double B1 = st1.y - st2.y , B2 = dir[npt1-1].y-dir[npt2-1].y;
		
	//	if(mid <= 0.9) printf("%lf %lf %lf %lf\n",A1,A2,B1,B2);
		double A = sqr(A2) + sqr(B2) , B = 2 * A1 * A2 + 2 * B1 * B2 , C = sqr(A1) + sqr(B1) - mid * mid;
		double delta = sqr(B) - 4 * A * C;
		
	//	if(mid<=0.9) printf("%lf %lf %lf %lf\n",A,B,C,delta);
	//	if(mid<=0.9)printf("%lf %lf %lf\n",tnow,lim1,lim2);
		
		if(dcmp(delta) == -1) 
			Insert(tnow , min(lim1,lim2));
		else
		{
			delta = sqrt(delta);
			if(dcmp(A) != 0)
			{		
				double x1 = (-B-delta)/(2*A) , x2 = (-B+delta)/(2*A);
	//			if(mid<= 0.9) 
	//				printf("%lf %lf\n",x1,x2);
				if(x1 > 0)
					Insert(tnow , min(min(lim1,lim2),tnow + x1));
				if(x2+tnow < min(lim1,lim2))
					Insert(max(x2+tnow,tnow),min(lim1,lim2));
			}
			else if(dcmp(B) == 0)
			{	
				if(C > 0) Insert(tnow,min(lim1,lim2));
			}
			else if(dcmp(B) == 1)
			{
				double x = - C / B;
				Insert(max(tnow,tnow+x),min(lim1,lim2));
			}
			else
			{
				double x = -C / B;
				Insert(tnow,min(min(lim1,lim2),tnow+x));
			}
		}
		
		double tnxt = min(lim1,lim2);
	//	if(mid>=1.02 && mid <= 1.04)
	//		printf("%lf\n",tnxt);
		if(dcmp(lim1-tnxt)!=1) st1=P[npt1],npt1++;
		else st1 = st1 + dir[npt1-1] * (tnxt - tnow);
		if(dcmp(lim2-tnxt)!=1) st2=P[npt2],npt2++;
		else st2 = st2 + dir[npt2-1] * (tnxt - tnow);
		
		tnow = tnxt;
	}
	if(ERROR) return 0;
	
	double Max = eps;
	for(int i=1;i<=cnt_t;i++) ct[i] =i;
	sort(ct+1,ct+1+cnt_t,cmp);
	
	//if(mid >= 1.02 && mid <= 1.04)
	//{
	//	for(int i=1;i<=cnt_t;i++)
	//	printf("%lf %lf\n",tl[ct[i]],tr[ct[i]]);
	//printf("\n");
	//}
	
	for(int i=1;i<=cnt_t;i++)
	{
		if(dcmp(tl[ct[i]]-Max) == 1)
		{
			return 1;
		}
		Max = max(Max , tr[ct[i]]);
	}
	if(dcmp(Max-C) == -1) return 1;
	return 0;
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lf%lf",&P[i].x,&P[i].y);
	P[n+1] = P[1];
	for(int i=1;i<=n;i++) 
		len[i] = dist(P[i],P[i+1]) , 
		C+=len[i] , arrtim[i+1] = C,
		dir[i] = (P[i+1] - P[i])*(1/(P[i+1]-P[i]).Len());
	for(int i=1;i<=n;i++)
		arrtim[n+i+1] = C + arrtim[i+1],
		dir[i+n] = dir[i],
		P[i+n] = P[i] , len[i+n] = len[i];
		
	C /= m;
	int id = 1;
	double sel = C;
	for(;dcmp(len[id]-sel)!=1;id++) sel-=len[id];
	id = (id-1) + 1;
	st = P[id] + dir[id] * sel;
	npt = id + 1;
	
	double l = 0 , r = 10000 , mid;
	for(;r-l>eps;)
	{
		mid = (l+r) * 0.5;
		if(check(mid)) r = mid;
		else l = mid + eps;
	}
	
	printf("%.7lf",l);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值