• BZOJ3775 : 点和直线


         设第$i$条直线的解析式为$a_ix+b_iy+c_i=0$,$d_i=a_i^2+b_i^2$,则要求一个点$(x,y)$,使得$sumleft(frac{left|a_ix+b_iy+c_i ight|}{sqrt{d_i}} ight)^2$最小。

                假设$x$固定,则

                [egin{eqnarray*}ans&=&sumleft(frac{left|a_ix+b_iy+c_i ight|}{sqrt{d_i}} ight)^2\&=&sumfrac{left(a_ix+b_iy+c_i ight)^2}{d_i}\&=&sumfrac{left(b_iy+a_ix+c_i ight)^2}{d_i}\&=&sumleft(frac{b_i^2y^2}{d_i}+frac{2b_ileft(a_ix+c_i ight)y}{d_i}+frac{left(a_ix+c_i ight)^2}{d_i} ight)\&=&sumfrac{b_i^2y^2}{d_i}+sumfrac{2b_ileft(a_ix+c_i ight)y}{d_i}+sumfrac{left(a_ix+c_i ight)^2}{d_i}\&=&y^2sumfrac{b_i^2}{d_i}+2ysumfrac{b_ileft(a_ix+c_i ight)}{d_i}+sumfrac{left(a_ix+c_i ight)^2}{d_i}\&=&y^2sumfrac{b_i^2}{d_i}+2yleft(sumfrac{a_ib_ix}{d_i}+sumfrac{b_ic_i}{d_i} ight)+sumfrac{left(a_ix+c_i ight)^2}{d_i}\&=&y^2sumfrac{b_i^2}{d_i}+2yleft(xsumfrac{a_ib_i}{d_i}+sumfrac{b_ic_i}{d_i} ight)+sumfrac{left(a_ix+c_i ight)^2}{d_i}end{eqnarray*}]

                当$y$取对称轴时取得最小值,此时

                [egin{eqnarray*}y&=&-frac{2left(xsumfrac{a_ib_i}{d_i}+sumfrac{b_ic_i}{d_i} ight)}{2sumfrac{b_i^2}{d_i}}\&=&-frac{xsumfrac{a_ib_i}{d_i}+sumfrac{b_ic_i}{d_i}}{sumfrac{b_i^2}{d_i}}\&=&-frac{sumfrac{a_ib_i}{d_i}}{sumfrac{b_i^2}{d_i}}x-frac{sumfrac{b_ic_i}{d_i}}{sumfrac{b_i^2}{d_i}}\&=&Ax+B\A&=&-frac{sumfrac{a_ib_i}{d_i}}{sumfrac{b_i^2}{d_i}}\B&=&-frac{sumfrac{b_ic_i}{d_i}}{sumfrac{b_i^2}{d_i}}end{eqnarray*}]

                将$y$用$Ax+B$表示,则

                [egin{eqnarray*}ans&=&sumfrac{left(a_ix+b_iy+c_i ight)^2}{d_i}\&=&sumfrac{left(a_ix+b_ileft(Ax+B ight)+c_i ight)^2}{d_i}\&=&sumfrac{left(a_ix+Ab_ix+Bb_i+c_i ight)^2}{d_i}\&=&sumfrac{left(left(a_i+Ab_i ight)x+Bb_i+c_i ight)^2}{d_i}\&=&sumfrac{left(a_i+Ab_i ight)^2x^2+2left(a_i+Ab_i ight)left(Bb_i+c_i ight)x+left(Bb_i+c_i ight)^2}{d_i}\&=&sumleft( frac{left(a_i+Ab_i ight)^2x^2}{d_i}+frac{2left(a_i+Ab_i ight)left(Bb_i+c_i ight)x}{d_i}+frac{left(Bb_i+c_i ight)^2}{d_i} ight)\&=&x^2sumfrac{left(a_i+Ab_i ight)^2}{d_i}+2xsumfrac{left(a_i+Ab_i ight)left(Bb_i+c_i ight)}{d_i}+sumfrac{left(Bb_i+c_i ight)^2}{d_i}\&=&Ux^2+Vx+W\U&=&sumfrac{left(a_i+Ab_i ight)^2}{d_i}\&=&sumfrac{a_i^2+2Aa_ib_i+A^2b_i^2}{d_i}\&=&sumfrac{a_i^2}{d_i}+2Asumfrac{a_ib_i}{d_i}+A^2sumfrac{b_i^2}{d_i}\V&=&2sumfrac{left(a_i+Ab_i ight)left(Bb_i+c_i ight)}{d_i}\&=&2sumfrac{Ba_ib_i+a_ic_i+ABb_i^2+Ab_ic_i}{d_i}\&=&2left(Bsumfrac{a_ib_i}{d_i}+sumfrac{a_ic_i}{d_i}+ABsumfrac{b_i^2}{d_i}+Asumfrac{b_ic_i}{d_i} ight)\W&=&sumfrac{left(Bb_i+c_i ight)^2}{d_i}\&=&sumfrac{B^2b_i^2+2Bb_ic_i+c_i^2}{d_i}\&=&B^2sumfrac{b_i^2}{d_i}+2Bsumfrac{b_ic_i}{d_i}+sumfrac{c_i^2}{d_i}end{eqnarray*}]

                若$U=0$,则最小值为$W$,否则当$x$取对称轴时取得最小值,此时$x=-frac{V}{2U}$,假设我们已经知道了$sumfrac{a_i^2}{d_i},sumfrac{b_i^2}{d_i},sumfrac{c_i^2}{d_i},sumfrac{a_ib_i}{d_i},sumfrac{a_ic_i}{d_i},sumfrac{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
    ",ans);
        }
      }
      return 0;
    }
    

      

  • 相关阅读:
    随手乱记
    对拍程序
    生命游戏
    Command Operating System by cdsidi(ComSys) 0.2.x版本陆续更新
    C语言<stdio.h>的rename函数——重命名文件、更改文件路径或更改目录名
    C++ 类中的static 成员函数
    Command Operating System by cdsidi(ComSys) 0.1.x版本陆续更新
    Command Operating System by cdsidi (ComSys)首次发布(版本0.1.2)
    区间dp之 "石子合并"系列(未完结)
    C/C++快读(快速读入)有多——安全AC
  • 原文地址:https://www.cnblogs.com/clrs97/p/4403197.html
Copyright © 2020-2023  润新知