zoukankan      html  css  js  c++  java
  • [luogu7340]Balance

    构造一个坐标系,共有$n$个黑点和百点,第$i$个黑点为$(p_{i},a_{i})$,第$i$个白点为$(-q_{i},-b_{i})$

    考虑第$i$个黑点和第$j$个白点连线的斜率,恰好就是$f(i,j)$

    根据$p_{i},q_{i}>0$,注意到黑点一定在白点右侧,且恰好从$y$轴将两者分开

    对于$f(i,j)$,若其是所有$f(i,k)$($1le kle n$)中第$x$小,这也就等价于存在$x$个白点在第$i$个黑点和第$j$个白点连线的上方(包括线上)且严格在其上方的白点数小于$x$个

    (对于这些白点,其与第$i$个黑点的连线斜率一定比第$j$个白点小)

    类似地,$f(i,j)$是所有$f(k,j)$($1le kle n$)中第$y$小,也就等价于存在$y$个黑点在第$i$个黑点和第$j$个白点连线的下方(包括线上)且严格在其下方的黑点数小于$y$个

    从中,可以发现合法性仅与这条直线有关,且当直线确定后,从其上任取一个黑点和白点即为答案

    (不难证明若其满足上述条件,则一定存在这样的黑点和白点)

    从几何的角度来说,一个点$P$在直线$l$上方,等价于过$P$作与$l$平行的直线后其截距大于$l$的截距(如果允许在直线$l$上即后面变为大于等于)

    当确定斜率后,过所有白点作一条该斜率的直线,也就是要找到与$y$轴交点上从上往下第$x$个交点,如果该斜率可行,那么必然是这条直线,然后我们检验另外一个条件即可

    斜率是具备单调性的,具体来说,随着斜率的增长,这个截距也一定向上移动,那么直线下的黑点数也单调递增,即单调(特别的,相等时应令$r=mid$)

    时间复杂度为$o(nlog n)$(具体实现可以利用nth_element函数),可以通过

    (代码会挂掉,大概是因为浮点误差)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 500005
     4 #define eps 1e-6
     5 int t,n,x,y,a[N],b[N],p[N],q[N],id[N];
     6 double tmp;
     7 bool cmp(int x,int y){
     8     return q[x]*tmp-b[x]>q[y]*tmp-b[y];
     9 }
    10 void read(int &x){
    11     int flag=x=0;
    12     char c=getchar();
    13     while ((c<'0')||(c>'9')){
    14         if (c=='-')flag=1;
    15         c=getchar();
    16     }
    17     while ((c>='0')&&(c<='9')){
    18         x=x*10+c-'0';
    19         c=getchar();
    20     }
    21     if (flag)x=-x;
    22 }
    23 int get(double k){
    24     tmp=k;
    25     for(int i=1;i<=n;i++)id[i]=i;
    26     nth_element(id+1,id+x,id+n+1,cmp);
    27     return id[x];
    28 }
    29 int calc(double k){
    30     int x0=get(k),ans=0;
    31     double c=q[x0]*k-b[x0];
    32     for(int i=1;i<=n;i++)
    33         if (a[i]-k*p[i]<=c+eps)ans++;
    34     return ans;
    35 }
    36 int main(){
    37     read(t);
    38     while (t--){
    39         read(n),read(x),read(y);
    40         for(int i=1;i<=n;i++)read(a[i]),read(b[i]),read(p[i]),read(q[i]);
    41         double l=-2e9,r=2e9;
    42         while (r-l>eps){
    43             double mid=(l+r)/2;
    44             if (calc(mid)>=y)r=mid;
    45             else l=mid;
    46         }
    47         l=r;
    48         int x0=get(l);
    49         for(int i=1;i<=n;i++)
    50             if (fabs((a[i]-l*p[i])-(q[x0]*l-b[x0]))<=eps){
    51                 printf("%d %d
    ",i,x0);
    52                 break;
    53             }
    54     }
    55 }
    View Code
  • 相关阅读:
    BZOJ 1576 树剖+LCT
    CF1051D Bicolorings 递推
    CF938D Buy a Ticket dijkstra
    记一次创建svc代理失败
    K8S中Service
    K8S中的Job和CronJob
    K8S中DaemonSet
    Linux expect介绍和用法
    Java根据余弦定理计算文本相似度
    Python和Sublime的整合
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14429775.html
Copyright © 2011-2022 走看看