BZOJ 2508: 简单题

题目大意:

加入直线,删除直线,求点到所有直线的距离的平方和。

题解:

把点到直线的距离公式写出来,然后展开。维护六个值,计算一个二元的多项式的最小值。

对x和y分别求导,导数都为零时取到极值。然后解一个方程组。

要各种讨论,方程的解可能不唯一,任取一个。

代码:

#include<cstdio>
#define eps 1e-7
using namespace std;
double x1[1000005],y1[1000005],x2[1000005],y2[1000005],A,B,C,D,E,F;
double abs1(double x){
	if (x<0) return -x;
	return x;
}
int main(){
	int t;
	scanf("%d",&t);
	int cnt=0;
	while (t--){
		int cas;
		scanf("%d",&cas);
		if (cas==0){
			cnt++;
			scanf("%lf%lf%lf%lf",&x1[cnt],&y1[cnt],&x2[cnt],&y2[cnt]);
			double ai=y1[cnt]-y2[cnt],bi=x2[cnt]-x1[cnt],ci=x1[cnt]*y2[cnt]-x2[cnt]*y1[cnt];
			A+=ai*ci*2/(ai*ai+bi*bi);
			B+=bi*ci*2/(ai*ai+bi*bi);
			C+=ai*bi*2/(ai*ai+bi*bi);
			D+=ai*ai/(ai*ai+bi*bi);
			E+=bi*bi/(ai*ai+bi*bi);
			F+=ci*ci/(ai*ai+bi*bi);
		}
		else if (cas==1){
			int id;
			scanf("%d",&id);
			double ai=y1[id]-y2[id],bi=x2[id]-x1[id],ci=x1[id]*y2[id]-x2[id]*y1[id];
			A-=ai*ci*2/(ai*ai+bi*bi);
			B-=bi*ci*2/(ai*ai+bi*bi);
			C-=ai*bi*2/(ai*ai+bi*bi);
			D-=ai*ai/(ai*ai+bi*bi);
			E-=bi*bi/(ai*ai+bi*bi);
			F-=ci*ci/(ai*ai+bi*bi);
		}
		else if (cas==2){
			double x,y;
			if (abs1(C*C-4*D*E)<eps){
				double a1,b1,c1;
				if (abs1(D)>eps || abs1(C)>eps) a1=2*D,b1=C,c1=A;
				else if (abs1(E)>eps || abs1(C)>eps) a1=C,b1=2*E,c1=B;
				else {
					printf("%.2lf\n",0.0);
					continue;
				}
				if (abs1(E)<eps) x=-c1/a1,y=0;
				else x=0,y=-c1/b1;
			}
			else if (abs1(C)<eps){
				if (abs1(D)<eps) x=0;
				else x=-A/(D*2);
				if (abs1(E)<eps) y=0;
				else y=-B/(E*2);
			}
			else if (abs1(D)<eps){
				y=-A/C;
				x=(-E*y*2-B)/C;
			}
			else if (abs1(E)<eps){
				x=-B/C;
				y=(-x*D*2-A)/C;
			}
			else{
				if (abs1(E*2-C*C/(D*2))<eps) {
					printf("0.00\n");
					continue;
				}
				y=(-B+A*C/(D*2))/(E*2-C*C/(D*2));
				x=(-A-C*y)/(D*2);
			}
			printf("%.2f\n",A*x+B*y+C*x*y+D*x*x+E*y*y+F);
		}
	}
	return 0;
}

  

posted @ 2018-04-13 16:23  ~Silent  阅读(182)  评论(0编辑  收藏  举报
Live2D