BZOJ3775 : 点和直线
设第$i$条直线的解析式为$a_ix+b_iy+c_i=0$,$d_i=a_i^2+b_i^2$,则要求一个点$(x,y)$,使得$\sum\left(\frac{\left|a_ix+b_iy+c_i\right|}{\sqrt{d_i}}\right)^2$最小。
假设$x$固定,则
\[\begin{eqnarray*}ans&=&\sum\left(\frac{\left|a_ix+b_iy+c_i\right|}{\sqrt{d_i}}\right)^2\\&=&\sum\frac{\left(a_ix+b_iy+c_i\right)^2}{d_i}\\&=&\sum\frac{\left(b_iy+a_ix+c_i\right)^2}{d_i}\\&=&\sum\left(\frac{b_i^2y^2}{d_i}+\frac{2b_i\left(a_ix+c_i\right)y}{d_i}+\frac{\left(a_ix+c_i\right)^2}{d_i}\right)\\&=&\sum\frac{b_i^2y^2}{d_i}+\sum\frac{2b_i\left(a_ix+c_i\right)y}{d_i}+\sum\frac{\left(a_ix+c_i\right)^2}{d_i}\\&=&y^2\sum\frac{b_i^2}{d_i}+2y\sum\frac{b_i\left(a_ix+c_i\right)}{d_i}+\sum\frac{\left(a_ix+c_i\right)^2}{d_i}\\&=&y^2\sum\frac{b_i^2}{d_i}+2y\left(\sum\frac{a_ib_ix}{d_i}+\sum\frac{b_ic_i}{d_i}\right)+\sum\frac{\left(a_ix+c_i\right)^2}{d_i}\\&=&y^2\sum\frac{b_i^2}{d_i}+2y\left(x\sum\frac{a_ib_i}{d_i}+\sum\frac{b_ic_i}{d_i}\right)+\sum\frac{\left(a_ix+c_i\right)^2}{d_i}\end{eqnarray*}\]
当$y$取对称轴时取得最小值,此时
\[\begin{eqnarray*}y&=&-\frac{2\left(x\sum\frac{a_ib_i}{d_i}+\sum\frac{b_ic_i}{d_i}\right)}{2\sum\frac{b_i^2}{d_i}}\\&=&-\frac{x\sum\frac{a_ib_i}{d_i}+\sum\frac{b_ic_i}{d_i}}{\sum\frac{b_i^2}{d_i}}\\&=&-\frac{\sum\frac{a_ib_i}{d_i}}{\sum\frac{b_i^2}{d_i}}x-\frac{\sum\frac{b_ic_i}{d_i}}{\sum\frac{b_i^2}{d_i}}\\&=&Ax+B\\A&=&-\frac{\sum\frac{a_ib_i}{d_i}}{\sum\frac{b_i^2}{d_i}}\\B&=&-\frac{\sum\frac{b_ic_i}{d_i}}{\sum\frac{b_i^2}{d_i}}\end{eqnarray*}\]
将$y$用$Ax+B$表示,则
\[\begin{eqnarray*}ans&=&\sum\frac{\left(a_ix+b_iy+c_i\right)^2}{d_i}\\&=&\sum\frac{\left(a_ix+b_i\left(Ax+B\right)+c_i\right)^2}{d_i}\\&=&\sum\frac{\left(a_ix+Ab_ix+Bb_i+c_i\right)^2}{d_i}\\&=&\sum\frac{\left(\left(a_i+Ab_i\right)x+Bb_i+c_i\right)^2}{d_i}\\&=&\sum\frac{\left(a_i+Ab_i\right)^2x^2+2\left(a_i+Ab_i\right)\left(Bb_i+c_i\right)x+\left(Bb_i+c_i\right)^2}{d_i}\\&=&\sum\left( \frac{\left(a_i+Ab_i\right)^2x^2}{d_i}+\frac{2\left(a_i+Ab_i\right)\left(Bb_i+c_i\right)x}{d_i}+\frac{\left(Bb_i+c_i\right)^2}{d_i}\right)\\&=&x^2\sum\frac{\left(a_i+Ab_i\right)^2}{d_i}+2x\sum\frac{\left(a_i+Ab_i\right)\left(Bb_i+c_i\right)}{d_i}+\sum\frac{\left(Bb_i+c_i\right)^2}{d_i}\\&=&Ux^2+Vx+W\\U&=&\sum\frac{\left(a_i+Ab_i\right)^2}{d_i}\\&=&\sum\frac{a_i^2+2Aa_ib_i+A^2b_i^2}{d_i}\\&=&\sum\frac{a_i^2}{d_i}+2A\sum\frac{a_ib_i}{d_i}+A^2\sum\frac{b_i^2}{d_i}\\V&=&2\sum\frac{\left(a_i+Ab_i\right)\left(Bb_i+c_i\right)}{d_i}\\&=&2\sum\frac{Ba_ib_i+a_ic_i+ABb_i^2+Ab_ic_i}{d_i}\\&=&2\left(B\sum\frac{a_ib_i}{d_i}+\sum\frac{a_ic_i}{d_i}+AB\sum\frac{b_i^2}{d_i}+A\sum\frac{b_ic_i}{d_i}\right)\\W&=&\sum\frac{\left(Bb_i+c_i\right)^2}{d_i}\\&=&\sum\frac{B^2b_i^2+2Bb_ic_i+c_i^2}{d_i}\\&=&B^2\sum\frac{b_i^2}{d_i}+2B\sum\frac{b_ic_i}{d_i}+\sum\frac{c_i^2}{d_i}\end{eqnarray*}\]
若$U=0$,则最小值为$W$,否则当$x$取对称轴时取得最小值,此时$x=-\frac{V}{2U}$,假设我们已经知道了$\sum\frac{a_i^2}{d_i},\sum\frac{b_i^2}{d_i},\sum\frac{c_i^2}{d_i},\sum\frac{a_ib_i}{d_i},\sum\frac{a_ic_i}{d_i},\sum\frac{b_ic_i}{d_i}$,则答案可以$O(1)$求出。
对于修改操作,只要$O(1)$修改这六个值即可。
至此,本题在$O(N)$复杂度内被解决。
#include<cstdio>
#include<cmath>
#define N 120010
int n,q,op,i,m;
double X1,X2,Y1,Y2,a,b,c,d,aa[N],bb[N],cc[N],ab[N],ac[N],bc[N],saa,sbb,scc,sab,sac,sbc,eps=1e-8,ans;
inline bool zero(double x){return std::fabs(x)<eps;}
inline double solve(double a,double b,double c){
if(zero(a))return c;
double x=-b/(2.0*a);
return a*x*x+b*x+c;
}
int main(){
scanf("%d",&q);
while(q--){
scanf("%d",&op);
if(op==0){
scanf("%lf%lf%lf%lf",&X1,&Y1,&X2,&Y2);
if(zero(X1-X2))a=1,b=0,c=-X1;else a=(Y2-Y1)/(X2-X1),b=-1,c=Y1-a*X1;
d=a*a+b*b;
aa[++n]=a*a/d,bb[n]=b*b/d,cc[n]=c*c/d,ab[n]=a*b/d,ac[n]=a*c/d,bc[n]=b*c/d;
saa+=aa[n],sbb+=bb[n],scc+=cc[n],sab+=ab[n],sac+=ac[n],sbc+=bc[n];
m++;
}
if(op==1){
scanf("%d",&i);
saa-=aa[i],sbb-=bb[i],scc-=cc[i],sab-=ab[i],sac-=ac[i],sbc-=bc[i];
m--;
}
if(op==2){
if(!m){puts("0.00");continue;}
if(zero(sbb))a=b=0;else a=-sab/sbb,b=-sbc/sbb;
ans=solve(saa+2.0*a*sab+a*a*sbb,2.0*(b*sab+sac+a*b*sbb+a*sbc),b*b*sbb+2.0*b*sbc+scc);
if(zero(ans))ans=0;
printf("%.2f\n",ans);
}
}
return 0;
}
BZOJ3775 : 点和直线的更多相关文章
- BZOJ3775: 点和直线(计算几何+拉格朗日乘数法)
题面 传送门 题解 劲啊-- 没有和\(Claris\)一样推,用了类似于\(Shinbokuow\)推已知点求最短直线的方法,结果\(WA\)了好几个小时,拿\(Claris\)代码拍了几个小时都没 ...
- MFC中如何画带实心箭头的直线
工作中遇到话流程图的项目,需要画带箭头的直线,经过摸索,解决:思路如下: (1) 两个点(p1,p2)确定一个直线,以直线的一个端点(假设p2)为原点,设定一个角度 (2)以P2为原点得到向量P2P1 ...
- 水平可见直线 bzoj 1007
水平可见直线 (1s 128M) lines [问题描述] 在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则Li为被覆 ...
- SVG:linearGradient渐变在直线上失效的问题解决方案
SVG开发里有个较为少见的问题. 对x1=x2或者y1=y2的直线(line以及path),比如: <path d="M200,10 200,100" stroke=&quo ...
- 封装 用canvas绘制直线的函数--面向对象
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- [bzoj1007][HNOI2008][水平可见直线] (斜率不等式)
Description 在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为 可见的,否则Li为被覆盖的. 例如,对于直线: L1:y ...
- [LeetCode] Line Reflection 直线对称
Given n points on a 2D plane, find if there is such a line parallel to y-axis that reflect the given ...
- 点(x3,y3)到经过点(x1,y1)和点(x2,y2)的直线的最短距离
/// <summary> /// 点(x3,y3)到经过点(x1,y1)和点(x2,y2)的直线的最短距离 /// </summary> /// <param name ...
- CoreGraphics-基本图形绘制-直线、三角形、矩形、椭圆形、弧形
框架:CoreGraphics 步骤: 1."获取"图形上下文 let cxtRef = UIGraphicsGetCurrentContext()! 2.添加路径 3.渲 ...
随机推荐
- 【Django】Django 如何支持 分组查询、统计?
代码: from django.db.models import Sum alarm_sum_group_items = models.FILE_PROTECT_ALARM.objects.filte ...
- 【云计算】docker registry v2简介
ubuntu docker方式部署docker registry v2 2016-03-03 17:36 by JackieHan, 4 阅读, 0 评论, 收藏, 编辑 生成自己签名的证书 生成签 ...
- eclipse workspace 共享配置文件
eclipse workspace 共享设置 配置文件记录了原来工程的使用习惯,如字体.编码格式等等,通过拷贝替换达到共享配置的目的. 总结一下,复制工作空间配置步骤如下: 1 使用eclipse新建 ...
- php-fpm启动
2014年6月30日 11:52:17 遇到一个问题,安装了redis.so后无论怎么重启nginx 还是 php-fpm都无法加载redis 最后发现重启php-fpm的参数弄错了 要这样: ./p ...
- ORACLE清除某一字段重复的数据(选取重复数据中另一个字段时期最大值)
需求:资产维修表中同一资产可能维修完继续申请维修,这时候维修状态需要根据最近的维修时间去判断维修状态,所以同一资产ID下会出现重复的数据(维修审批通过,维修审批未通过),或者可能不出现(未申请维修), ...
- UVALive 7269 Snake Carpet (构造)
题目:传送门. 题意:构造出一个矩阵,使得矩阵含有n条蛇,每条蛇的长度是1到n,并且奇数长度的蛇有奇数个拐弯,偶数长度 的蛇有偶数个拐弯. 奇数和偶数分开构造,奇数可以是: 1357 3357 555 ...
- HDU 5514 Frogs (容斥原理+因子分解)
题目链接 题意:有n只青蛙,m个石头(围成圆圈).第i只青蛙每次只能条ai个石头,问最后所有青蛙跳过的石头的下标总和是多少? 题解:暴力肯定会超时,首先分解出m的因子,自己本身不用分,因为石头编号是0 ...
- atan函数与atan2函数
atan函数:传送门. atan2函数:传送门. atan 和 atan2 都是求反正切函数,如:有两个点 point(x1,y1), 和 point(x2,y2); 那么这两个点形成的斜率的角度计算 ...
- Intellj IDEA快捷键
Alt+回车 导入包,自动修正 Ctrl+N 查找类 Ctrl+Shift+N 查找文件 Ctrl+Alt+L 格式化代码 Ctrl+Alt+O 优化导入的类和包 Alt+Insert 生成代码 ...
- ubuntu使用root账户登录
1.先设定一个root的密码 sudo passwd root 2.编辑lightdm.conf sudo gedit /etc/lightdm/lightdm.conf 最后一行添加 greeter ...