• 【SDOI2018】物理实验


    题目

    考虑让直线导轨成为(x)轴,钦定((x_1,y_1))成为坐标原点,其余点的坐标都减去((x_1,y_1))。之后需要使得((x_2,y_2))落在(x)轴上,求一下((x_2,y_2))(x)轴的夹角(alpha),让所有点都顺时针旋转(alpha)就好了。

    点旋转后的坐标变换是老经典问题了,((x,y))顺时针旋转(alpha)之后就变成了((xcosalpha+ysinalpha,-xsinalpha+ycos alpha))

    考虑一段挡板在(x)轴的投影是([l,r]),这段挡板到(x)轴的夹角为(eta);如果激光发射器与投影的交长度为(l),那么就会在挡板被激光照射到的长度就是(frac{l}{coseta})

    这表明了我们一定能将所有挡板都转化成((l,r,v))的形式,即这段挡板在(x)轴上的投影为([l,r]),极角余弦值的倒数为(v);这样对答案的影响就是,(v)乘上投影与激光发射器的交的长度

    考虑处理出所有的((l,r,v)),由于挡板不能被激光穿过,所以只保留距离(x)轴最近的挡板;对于一条线段((x_1,y_1,x_2,y_2)),视为在(x_1)处插入它,在(x_2)处将其删除;用(set)来维护当前距离(x)轴最近的线段。由于题目中保证了任意两条线段不会相互接触,于是在两个相邻的端点之间最靠近(x)轴的线段只有一条。直接访问(set)的begin迭代器即可。

    显然我们可以在(O(1))的时间内判断两条线段谁更更靠近(x)轴,于是可以直接给(set)写一个比较函数,这样就非常方便。

    最后将问题转化成了找到一个长度为(L)的线段,使得这条线段与投影的带权交最大。

    不难发现将线段的端点卡在投影的端点处会取到最优的答案,于是我们将所有投影排好序,正反两边双指针即可。

    于是这样就做完了,时间复杂度(O(Tnlog n))

    然而实际上非常难写,我们求投影的时候要分在(x)轴上方和下方两种情况分别求,分别求完之后还需要合并,双指针的时候也得进行一番讨论。

    据说十分卡精度,还需要long double,但是直接用double就莽过去了也是非常刺激。

    代码

    #include<bits/stdc++.h>
    #define db double
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read() {
    	char c=getchar();int r=1,x=0;while(c<'0'||c>'9'){if(c=='-')r=-1;c=getchar();};
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48,c=getchar();return x*r;
    }
    const db Pi=acos(-1),eps=1e-15;
    const int maxn=5e4+5;
    struct Pt{db x,y;}S,E;
    struct Line{Pt s,t;}L[maxn];
    struct wkL{db p,v;int o,rk;}a[maxn<<1];
    struct Seg{db l,r,v;}seg[2][maxn<<1],b[maxn<<4];
    struct Point{db p,v;int o;}d[maxn<<2];
    int n,Len,tot,sz[2],cnt,num;db val[maxn];
    inline int dcmp(db A,db B) {return A+eps>B&&A-eps<B;}
    inline int cmp(const wkL &A,const wkL &B) {return A.p<B.p;}
    inline int ctp(const Point &A,const Point &B) {return A.p<B.p;}
    inline db operator*(const Pt &A,const Pt &B) {return A.x*B.y-A.y*B.x;}
    inline Pt operator+(const Pt &A,const Pt &B) {return (Pt){A.x+B.x,A.y+B.y};}
    inline Pt operator-(const Pt &A,const Pt &B) {return (Pt){A.x-B.x,A.y-B.y};}
    inline Pt rotate(const Pt &A,db det) {
    	db s=sin(det),c=cos(det);
    	return (Pt){A.x*c+A.y*s,A.y*c-A.x*s};
    }
    struct cop {
    	bool operator() (int A,int B) {
    		if(L[A].s.x<L[B].s.x) {
    			db t=L[B].s.x-L[A].s.x;
    			t*=(L[A].t.y-L[A].s.y);
    			t/=(L[A].t.x-L[A].s.x);
    			t+=L[A].s.y;
    			return t<L[B].s.y;
    		}
    		else {
    			db t=L[A].s.x-L[B].s.x;
    			t*=(L[B].t.y-L[B].s.y);
    			t/=(L[B].t.x-L[B].s.x);
    			t+=L[B].s.y;
    			return L[A].s.y<t;
    		}
    	}
    };
    std::set<int,cop> s;
    inline void calc(int op) {
    	std::sort(a+1,a+tot+1,cmp);
    	for(re int i=1;i<=tot;++i) 	
    		if(a[i].o==1) val[a[i].rk]=a[i].v;
    	db nw=-1e18;s.clear();
    	for(re int i=1;i<=tot;++i) {
    		if(!s.empty()&&!dcmp(nw,a[i].p)) {
    			seg[op][++sz[op]].l=nw;
    			seg[op][sz[op]].r=a[i].p;
    			seg[op][sz[op]].v=val[*(s.begin())];
    		}
    		nw=a[i].p;
    		if(a[i].o==-1) s.erase(a[i].rk);
    		if(a[i].o==1) s.insert(a[i].rk);
    	}
    }
    inline void Main_solve() {
    	n=read();
    	for(re int i=1;i<=n;i++) 
    		L[i].s.x=read(),L[i].s.y=read(),L[i].t.x=read(),L[i].t.y=read();
    	S.x=read(),S.y=read(),E.x=read(),E.y=read(),Len=read();
    	for(re int i=1;i<=n;i++)L[i].s=L[i].s-S,L[i].t=L[i].t-S;E=E-S;
    	db Det=atan2(E.y,E.x);
    	for(re int i=1;i<=n;i++)L[i].s=rotate(L[i].s,Det);
    	for(re int i=1;i<=n;i++)L[i].t=rotate(L[i].t,Det);
    	for(re int i=1;i<=n;i++) 
    		if(L[i].s.x>L[i].t.x) std::swap(L[i].s,L[i].t);
    	tot=0;sz[0]=sz[1]=0;
    	for(re int i=1;i<=n;i++) 
    		if(L[i].s.y>0) {
    			db det=atan2((L[i].t-L[i].s).y,(L[i].t-L[i].s).x);
    			det=1.0/cos(det);
    			a[++tot].p=L[i].s.x;
    			a[tot].o=1;
    			a[tot].v=det;
    			a[tot].rk=i;
    			a[++tot].p=L[i].t.x;
    			a[tot].o=-1;
    			a[tot].rk=i;
    		}
    	calc(0);tot=0;
    	for(re int i=1;i<=n;i++) 
    		if(L[i].s.y<0) {
    			L[i].s.y=fabs(L[i].s.y);
    			L[i].t.y=fabs(L[i].t.y);
    			db det=atan2((L[i].t-L[i].s).y,(L[i].t-L[i].s).x);
    			det=1.0/cos(det);
    			a[++tot].p=L[i].s.x;
    			a[tot].o=1;
    			a[tot].v=det;
    			a[tot].rk=i;
    			a[++tot].p=L[i].t.x;
    			a[tot].o=-1;
    			a[tot].rk=i;
    		}  
    	cnt=0,num=0;
    	calc(1);
    	for(re int i=1;i<=sz[0];i++) {
    		d[++cnt].p=seg[0][i].l;
    		d[cnt].o=1;d[cnt].v=seg[0][i].v;
    		d[++cnt].p=seg[0][i].r;
    		d[cnt].o=-1;d[cnt].v=-seg[0][i].v;
    	}
    	for(re int i=1;i<=sz[1];++i) {
    		d[++cnt].p=seg[1][i].l;
    		d[cnt].o=1;d[cnt].v=seg[1][i].v;
    		d[++cnt].p=seg[1][i].r;
    		d[cnt].o=-1;d[cnt].v=-seg[1][i].v;
    	}
    	std::sort(d+1,d+cnt+1,ctp);
    	db nw=-1e18,sv=0;int nsz=0;
    	for(re int i=1;i<=cnt;++i) {
    		if(nsz&&!dcmp(nw,d[i].p)) {
    			b[++num].l=nw;
    			b[num].r=d[i].p;
    			b[num].v=sv;
    		}
    		nsz+=d[i].o;sv+=d[i].v;nw=d[i].p;
    	}
    	int lp=1;db tmp=0,ans=0;
    	for(re int i=1;i<=num;++i) {
    		if(lp>=i) tmp-=(b[i-1].r-b[i-1].l)*b[i-1].v;
    		while(lp<=num&&(b[i].l+Len>b[lp].r||dcmp(b[i].l+Len,b[lp].r))) {
    			if(lp>=i) tmp+=(b[lp].r-b[lp].l)*b[lp].v;
    			++lp;
    		}
    		if(lp<=num) {
    			db t=(b[i].l+Len)-b[lp].l;
    			if(t<0)t=0;t*=b[lp].v;
    			ans=max(ans,t+tmp);
    		}else ans=max(ans,tmp);
    	}
    	for(re int i=1;i<=num;i++)std::swap(b[i].l,b[i].r),b[i].l=-b[i].l,b[i].r=-b[i].r;
    	std::reverse(b+1,b+num+1);
    	lp=1,tmp=0;
    	for(re int i=1;i<=num;++i) {
    		if(lp>=i) tmp-=(b[i-1].r-b[i-1].l)*b[i-1].v;
    		while(lp<=num&&(b[i].l+Len>b[lp].r||dcmp(b[i].l+Len,b[lp].r))) {
    			if(lp>=i) tmp+=(b[lp].r-b[lp].l)*b[lp].v;
    			++lp;
    		}
    		if(lp<=num) {
    			db t=(b[i].l+Len)-b[lp].l;
    			if(t<0)t=0;t*=b[lp].v;
    			ans=max(ans,t+tmp);
    		}else ans=max(ans,tmp);
    	}
    	printf("%.15lf
    ",ans);
    		 
    }
    int main() {
    	for(re int T=read();T;--T)Main_solve();
    	return 0;
    }
    
  • 相关阅读:
    What is tail-recursion
    Lua(1)
    递归与循环
    android屏幕适配
    Handler 与 Toast
    Android ViewGroup onInterceptTouchEvent
    Java Synchronized 与 ThreadLocal 异同
    Java Synchronized 遇上 静态/实例方法 、静态/实例变量
    Java Concurrent happens-before
    CM记录-JVM调优
  • 原文地址:https://www.cnblogs.com/asuldb/p/12987353.html
Copyright © 2020-2023  润新知