SDOI 2018 R2 T1 物理实验题解

题目链接: 点击打开链接loj
      首先将所有挡板翻转至以直线导轨为X轴的坐标系中,记录每个挡板两个端点的坐标,然后我们考虑如何处理挡板之间的遮挡情况,我们可以使用扫描线+set维护,我们将每个端点按x值排序,左端点记1 ,右端点记-1,然后我们可以用set维护在每段区间最下方的直线斜率是多少,遇到左端点在set中插入线段,遇到右端点,删除该线段。
      最后我们考虑如何O(n)的统计答案,首先我们注意到最后所选的导轨上的区间的两端点一定有一个卡在挡板的端点之一,然后我们区间向右移动所含的挡板区间也单调向右,扫一遍 左端点,扫一遍 右端点即可。
附代码:写丑了最好不要参考

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<set>
#define double  long double
using namespace std;
const double eps = 1e-13;
const double pi= acos(-1);
double curx;
struct node{
	double x,y,xx,yy;
}lin[1000010] , model;
struct straight{
	double a,b,c;
}lne;
struct node2{
	double x,y,k,xx,yy;
}nw1[1000010],nw2[1000010];
int t,n;
double l;
struct point
{
	int id,belong;
	double x,y;
}pt1[100100],pt2[100010];
struct line1{
	point aa,bb;
	double jieju,xielv;
	inline bool operator < (const line1 &p) const
	{
		return (jieju+xielv*curx)<(p.jieju+p.xielv*curx);
	}
}le1[1000010],le2[1000010];
void get(node x)
{
	if(fabs(x.x-x.xx)<eps)
	{
		lne.a=1;
		lne.b=0;
		lne.c=-x.x;
		return ;
	}
	if(fabs(x.yy-x.y)<eps)
	{
		lne.a=0;
		lne.b=1;
		lne.c=-x.y;
		return ;
	}
	double a=(x.y-x.yy)/(x.x-x.xx);
	double b=-1;
	double c=x.y-(x.y-x.yy)/(x.x-x.xx)*x.x;
	lne.a=a;
	lne.b=b;
	lne.c=c;
}
int getwhere(double x,double y)
{
	double tmp=lne.a*x+lne.c;
	if(tmp>y) return 1;
	else return 2;
}
bool cmp(node2 p,node2 q)
{
	return p.x<q.x;
}
double ans=0,ret=0;
bool cmpp(point p,point q)
{
	return p.x<q.x;
}
struct xianduan{
	double x,xx,k;
}ed1[500100],ed2[500010];
bool cmppp(xianduan p,xianduan q)
{
	if(p.x==q.x)
	return p.xx<q.xx;
	else return  p.x<q.x;
}
double sum[500010],summ[500010];
double work(int cnt1,int cnt2)
{
	for(register int i=1;i<=cnt1;++i) sum[i]=0;
	for(register int i=1;i<=cnt2;++i) summ[i]=0;
	double ret=0;
	ans=0;
	int ll=0,rr=0,ul=0,ur=0;
	for(register int i=1;i<=cnt1;++i)
	{
		double tmp=ed1[i].xx-ed1[i].x;
		double tmpp=tmp*ed1[i].k;
		sum[i]=sqrt(tmp*tmp+tmpp*tmpp);
		sum[i]+=sum[i-1];
	//	printf("%Lf %Lf %Lf %Lf\n",ed1[i].x,ed1[i].xx,ed1[i].k,sum[i]);
	}
	for(register int i=1;i<=cnt2;++i)
	{
		double tmp=ed2[i].xx-ed2[i].x;
		double tmpp=tmp*ed2[i].k;
		summ[i]=sqrt(tmp*tmp+tmpp*tmpp);
		summ[i]+=summ[i-1];
	//	printf("%Lf %Lf %Lf %Lf\n",ed2[i].x,ed2[i].xx,ed2[i].k,summ[i]);
	}
	for(register int i=1;i<=cnt1;++i)
	{
		ret=0;
		double left=ed1[i].x,rt=ed1[i].x+l;
		ll=i;
		while((ed1[rr].xx<rt||!rr)&&rr<cnt1) rr++;
		ret+=(sum[rr-1]-sum[i-1]);
		double tmp=min(rt,ed1[rr].xx)-max(left,ed1[rr].x);
		if(tmp>eps)
		{
			double tmpp=tmp*ed1[rr].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
		} 
		while((ed2[ul].xx<left||!ul)&&ul<cnt2) ul++;
		while((ed2[ur].xx<rt||!ur)&&ur<cnt2) ur++;
		ret+=max(summ[ur-1]-summ[ul],(double)0.0);
		if(ur==ul)
		{
			double tmp=min(rt,ed2[ur].xx)-max(left,ed2[ur].x);
			if(tmp>eps)
			{
				double tmpp=tmp*ed2[ur].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
			}
			if(ret>ans) ans=ret;
		}
		else
		{
			double tmp=min(rt,ed2[ur].xx)-max(left,ed2[ur].x);
			if(tmp>eps)
			{
				double tmpp=tmp*ed2[ur].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
			}
			tmp=min(rt,ed2[ul].xx)-max(left,ed2[ul].x);
			if(tmp>eps)
			{
				double tmpp=tmp*ed2[ul].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
			}
			if(ret>ans) ans=ret;
		}
	}
	ul=ur=ll=rr=0;
	for(register int i=1;i<=cnt1;++i)
	{
		ret=0;
		double left=ed1[i].xx-l,rt=ed1[i].xx;
		while((ed1[ll].xx<left||!ll)&&ll<cnt1) ll++;
		rr=i;
		ret+=(sum[rr]-sum[ll]);
		double tmp=min(rt,ed1[ll].xx)-max(left,ed1[ll].x);
		if(tmp>eps)
		{
			double tmpp=tmp*ed1[ll].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
		} 
		while((ed2[ul].xx<left||!ul)&&ul<cnt2) ul++;
		while((ed2[ur].xx<rt||!ur)&&ur<cnt2) ur++;
		ret+=max(summ[ur-1]-summ[ul],(double)0);
		if(ur==ul)
		{
			double tmp=min(rt,ed2[ur].xx)-max(left,ed2[ur].x);
			if(tmp>eps)
			{
				double tmpp=tmp*ed2[ur].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
			}
			if(ret>ans) ans=ret;
		}
		else
		{
			double tmp=min(rt,ed2[ur].xx)-max(left,ed2[ur].x);
			if(tmp>eps)
			{
				double tmpp=tmp*ed2[ur].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
			}
			tmp=min(rt,ed2[ul].xx)-max(left,ed2[ul].x);
			if(tmp>eps)
			{
				double tmpp=tmp*ed2[ul].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
			}
			if(ret>ans) ans=ret;
		}
	}
	ul=ur=ll=rr=0;
	for(register int i=1;i<=cnt2;++i)
	{
		ret=0;
		double left=ed2[i].xx-l,rt=ed2[i].xx;
		while((ed2[ll].xx<left||!ll)&&ll<cnt2)ll++;
		rr=i;
		ret+=(summ[rr]-summ[ll]);
		double tmp=min(rt,ed2[ll].xx)-max(left,ed2[ll].x);
		if(tmp>eps)
		{
			double tmpp=tmp*ed2[ll].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
		} 
		while((ed1[ul].xx<left||!ul)&&ul<cnt1) ul++;
		while((ed1[ur].xx<rt||!ur)&&ur<cnt1) ur++;
		ret+=max(sum[ur-1]-sum[ul],(double)0);
		if(ur==ul)
		{
			double tmp=min(rt,ed1[ur].xx)-max(left,ed1[ur].x);
			if(tmp>eps)
			{
				double tmpp=tmp*ed1[ur].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
			}
			if(ret>ans) ans=ret;
		}
		else
		{
			double tmp=min(rt,ed1[ur].xx)-max(left,ed1[ur].x);
			if(tmp>eps)
			{
				double tmpp=tmp*ed1[ur].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
			}
			tmp=min(rt,ed1[ul].xx)-max(left,ed1[ul].x);
			if(tmp>eps)
			{
				double tmpp=tmp*ed1[ul].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
			}
			if(ret>ans) ans=ret;
		}
	}
	ul=ur=ll=rr=0;
	for(register int i=1;i<=cnt2;++i)
	{
		ret=0;
		double left=ed2[i].x,rt=ed2[i].x+l;
		ll=i;
		while((ed2[rr].xx<rt||!rr)&&rr<cnt2) rr++;
		ret+=(summ[rr-1]-summ[i-1]);
		double tmp=min(rt,ed2[rr].xx)-max(left,ed2[rr].x);
		if(tmp>eps)
		{
			double tmpp=tmp*ed2[rr].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
		} 
		while((ed1[ul].xx<left||!ul)&&ul<cnt1) ul++;
		while((ed1[ur].xx<rt||!ur)&&ur<cnt1) ur++;
	//	printf("%Lf %Lf %d %d %d %d\n",left,rt,ll,rr,ul,ur);
		ret+=max(sum[ur-1]-sum[ul],(double)0);
		if(ur==ul)
		{
			double tmp=min(rt,ed1[ur].xx)-max(left,ed1[ur].x);
			if(tmp>eps)
			{
				double tmpp=tmp*ed1[ur].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
			}
			if(ret>ans) ans=ret;
		}
		else
		{
			double tmp=min(rt,ed1[ur].xx)-max(left,ed1[ur].x);
			if(tmp>eps)
			{
				double tmpp=tmp*ed1[ur].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
			}
			tmp=min(rt,ed1[ul].xx)-max(left,ed1[ul].x);
			if(tmp>eps)
			{
				double tmpp=tmp*ed1[ul].k;ret+=sqrt(tmp*tmp+tmpp*tmpp);
			}
			if(ret>ans) ans=ret;
		}
	//	cout<<endl<<ret<<endl;
	}
}
inline int read()
{
	int w=1,s=0;
	char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') w=-1;
		ch=getchar();
	}
	while(isdigit(ch))
	{
		s=s*10+ch-'0';
		ch=getchar();
	}
	return w*s;
}
int main(){
//	freopen("01.in","r",stdin);
//	freopen("laser.out","w",stdout);
	cin>>t;
	while(t--)
	{
		set< line1  > st;
		ans=0;
		curx=0;
		n=read();
		for(register int i=1;i<=n;++i)
		{
			int x,y;
			x=read(),y=read(); lin[i].x=x,lin[i].y=y;x=read(),y=read();lin[i].xx=x,lin[i].yy=y;
		}
		int x,y,xx,yy,ll;
		x=read();y=read();xx=read();yy=read();ll=read(); 
		model.x=x,model.y=y,model.xx=xx,model.yy=yy;l=ll;
		get(model);
		double degree;
		if(fabs(lne.a)>eps)
		degree=atan(lne.a);
		if(lne.a==0){
			degree=0;
		}
		if(lne.b==0)
		{
			degree=pi/2;
		}
		int cnt1=0,cnt2=0;
		for(register int i=1;i<=n;++i)
		{
			double tx=lin[i].x,ty=lin[i].y;
			double lx=lin[i].xx,ly=lin[i].yy;
			double a=lne.a,b=lne.b,c=lne.c;
			int op=getwhere(tx,ty);
			if(op==2)
			{
				cnt1++;
				nw1[cnt1].x=cos(degree)*tx+sin(degree)*ty;
				nw1[cnt1].y=abs(a*tx+b*ty+c)/sqrt(a*a+b*b);
				nw1[cnt1].xx=cos(degree)*lx+sin(degree)*ly;
				nw1[cnt1].yy=abs(a*lx+b*ly+c)/sqrt(a*a+b*b);
				nw1[cnt1].k=(nw1[cnt1].yy-nw1[cnt1].y)/(nw1[cnt1].xx-nw1[cnt1].x);
				if(nw1[cnt1].xx<nw1[cnt1].x) swap(nw1[cnt1].xx,nw1[cnt1].x),swap(nw1[cnt1].yy,nw1[cnt1].y);
				
			}
			if(op==1)
			{
				cnt2++;
				nw2[cnt2].x=cos(degree)*tx+sin(degree)*ty;
				nw2[cnt2].y=abs(a*tx+b*ty+c)/sqrt(a*a+b*b);
				nw2[cnt2].xx=cos(degree)*lx+sin(degree)*ly;
				nw2[cnt2].yy=abs(a*lx+b*ly+c)/sqrt(a*a+b*b);
				nw2[cnt2].k=(nw2[cnt2].yy-nw2[cnt2].y)/(nw2[cnt2].xx-nw2[cnt2].x);
				if(nw2[cnt2].xx<nw2[cnt2].x) swap(nw2[cnt2].xx,nw2[cnt2].x),swap(nw2[cnt2].yy,nw2[cnt2].y);
			}
		}
		int tot1=0,tot2=0;
		for(register int i=1;i<=cnt1;++i)
		{
			pt1[++tot1].x= nw1[i].x;pt1[tot1].y=nw1[i].y;pt1[tot1].id=1;pt1[tot1].belong=i;
			le1[i].aa=pt1[tot1];
			pt1[++tot1].x=nw1[i].xx;pt1[tot1].y=nw1[i].yy;pt1[tot1].id=-1;pt1[tot1].belong=i;
			le1[i].bb=pt1[tot1];
			le1[i].xielv=nw1[i].k;
			le1[i].jieju=(nw1[i].y-nw1[i].k*nw1[i].x);
		}
		for(register int i=1;i<=cnt2;++i)
		{
			pt2[++tot2].x= nw2[i].x;pt2[tot2].y=nw2[i].y;pt2[tot2].id=1;pt2[tot2].belong=i;
			le2[i].aa=pt2[tot2];
			pt2[++tot2].x=nw2[i].xx;pt2[tot2].y=nw2[i].yy;pt2[tot2].id=-1;pt2[tot2].belong=i;
			le2[i].bb=pt2[tot2];
			le2[i].xielv=nw2[i].k;
			le2[i].jieju=(nw2[i].y-nw2[i].k*nw2[i].x);
		}
		sort(pt1+1,pt1+tot1+1,cmpp);
		sort(pt2+1,pt2+tot2+1,cmpp);
		curx=pt1[1].x;
		cnt1=0;
		st.insert(le1[pt1[1].belong]);
		for(register int i=2;i<=tot1;++i)
		{
			int tmp=pt1[i].belong;
			if(pt1[i].id==1){
				if(!st.empty()){
					ed1[++cnt1].x=curx,ed1[cnt1].xx=pt1[i].x;line1 qaq=*st.begin();ed1[cnt1].k=qaq.xielv;
			}
			curx=pt1[i].x;st.insert(le1[tmp]);
			}
			if(pt1[i].id==-1)
			{
				if(!st.empty())
				{
					ed1[++cnt1].x=curx,ed1[cnt1].xx=pt1[i].x;line1 qaq=*st.begin();ed1[cnt1].k=qaq.xielv;
				}
				curx=pt1[i].x;
				st.erase(le1[tmp]);
			}
		}
		curx=pt2[1].x;
		cnt2=0;
		st.insert(le2[pt2[1].belong]);
		for(register int i=2;i<=tot2;++i)
		{
			int tmp=pt2[i].belong;
			if(pt2[i].id==1){if(!st.empty()){ed2[++cnt2].x=curx,ed2[cnt2].xx=pt2[i].x;line1 qaq=*st.begin();ed2[cnt2].k=qaq.xielv;};curx=pt2[i].x;st.insert(le2[tmp]);};
			if(pt2[i].id==-1)
			{
				if(!st.empty())
				{
					ed2[++cnt2].x=curx,ed2[cnt2].xx=pt2[i].x;line1 qaq=*st.begin();ed2[cnt2].k=qaq.xielv;
				}
				curx=pt2[i].x;
				st.erase(le2[tmp]);
			}
		}
		sort(ed1+1,ed1+cnt1+1,cmppp);
		sort(ed2+1,ed2+cnt2+1,cmppp);
		work(cnt1,cnt2);
		printf("%.15Lf\n",ans);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值