• csp-s模拟75 导弹袭击


    题解

      想了想,这道题还是需要大概写一下题解的。

      一开始比较显然的推柿子,可以得到$frac{(b_i-b_j)*a_i*a_j}{(a_j-a_i)*b_i*b_j}<=frac{A}{B}$的形式,然后暴力$n^2$$Check$就行,这样就有75分了。(加一个很显然的剪枝)

      然后正解。

      我们发现上面那个$frac{a_i}{b_i}$可以预处理出来,然后剩下了$frac{b_i-b_j}{a_j-a_i}$,我们好好看看这个柿子。
      它很像斜率??

      好像是有点像。那么我们考虑一下斜率这个问题。

      为了省略分数线,我们定义$x_i$为$frac{1}{a_i}$,设$y_i$为$frac{1}{b_i}$,然后考虑这个东西。

      我们的目的是为了使$x_i*A+y_i*B==Z$最小,那么对于任何的$j$,都要满足$x_i*A+y_i*B<=x_j*A+y_j*B$。因为最后的结果只与$A$、$B$之间的比值有关,我们不妨设$B==1$。我们化简一下,就可以到:

    $-frac{y_i-y_j}{x_i-x_j}>=A$

      这个柿子更加显然了,明显的凸包,并且是一个下凸包。

      在此说一下为什么是凸包。$A*x_i+y_i==Z$,移项,$y_i==-A*x_i+Z$,所以当A的取值越小,纵截距越小,因此我们要找的是斜率A的最小值,也就是上述分式的最大值。对于所有点,在相同斜率下最小的截距肯定是下凸包上的点,因此我们要维护一个下凸包。

      对于凸包,一定要牢记:比较的是不同点在相同斜率下的取值,并且以此为判断条件弹栈,不是不同的点以不同的斜率来判断。

      对于此题,可能会有点横坐标相同而纵坐标不同,我们要维护一个下凸包,那么可能的最优解一定是该横坐标下的最小的纵坐标。

      去一下重,然后差不多就没了,最后注意一下精度问题,用1除以1e9很容易爆炸啊,那用1000000.0除以1e9是不是好多了呢?

      答案是最后栈中元素。

     1 #include<cstdio>
     2 #include<vector>
     3 #include<algorithm>
     4 #define HZOI std
     5 using namespace HZOI;
     6 const int N=3e5+3;
     7 const int INF=0x3f3f3f3f;
     8 struct node{
     9     double x,y;
    10     int id,cnt;
    11     friend bool operator < (node X,node Y)
    12     {
    13         return X.x<Y.x;
    14     }
    15 }zb[N];
    16 struct SR{
    17     int a,b,id;
    18     friend bool operator < (SR X,SR Y)
    19     {
    20         return X.a!=Y.a?X.a>Y.a:X.b>Y.b;
    21     }
    22 }sr[N];
    23 int n,cnt;
    24 int tail,ans[N],res[N],stc[N],a[N],b[N];
    25 double c[N],minn,maxx;
    26 vector<int> vec[N];
    27 double Calc(int ,int );
    28 inline int read();
    29 double max(double x,double y) {return x>y?x:y;}
    30 double min(double x,double y) {return x<y?x:y;}
    31 int main()
    32 {
    33 //    freopen("slay4.in","r",stdin);
    34 //    freopen("test.in","r",stdin);
    35 //    freopen("1.out","w",stdout);
    36     n=read();
    37     for (int i=1,a,b; i<=n; ++i) sr[i].a=read(),sr[i].b=read(),sr[i].id=i;
    38     sort(sr+1,sr+n+1);
    39     int zz=0;
    40     for (int i=1; i<=n; ++i)
    41     {
    42         if (sr[i].a==sr[zz].a && sr[i].b==sr[zz].b) zb[cnt].cnt++,vec[cnt].push_back(sr[i].id),zz=i;
    43         else if (i!=1 && sr[i].a==sr[zz].a && sr[i].b!=sr[i].b) continue ;
    44         else if (i==1 || (sr[i].a<sr[zz].a && sr[i].b>=sr[zz].b))
    45             zb[++cnt]=(node){1000000.0/(double)sr[i].a,1000000.0/(double)sr[i].b,cnt,1},vec[cnt].push_back(sr[i].id),zz=i;
    46     }
    47     sort(zb+1,zb+cnt+1);
    48     for (int i=1; i<=cnt; ++i)
    49     {
    50         if (zb[i].x==zb[stc[tail]].x && zb[i].y==zb[stc[tail]].y) {stc[++tail]=i;continue ;}
    51         while (tail>1 && Calc(i,stc[tail])>Calc(stc[tail],stc[tail-1])) --tail;
    52         if (!tail) stc[++tail]=i;
    53         else if (tail && Calc(i,stc[tail])>0) stc[++tail]=i;
    54     }
    55     for (int i=1; i<=tail; ++i) ans[i]=zb[stc[i]].id;
    56     for (int i=1; i<=tail; ++i)
    57         for (int j=0; j<vec[ans[i]].size(); ++j)
    58             res[++res[0]]=vec[ans[i]][j];
    59     sort(res+1,res+res[0]+1);
    60     for (int i=1; i<=res[0]; ++i) printf("%d ",res[i]);
    61     return 0;
    62 }
    63 double Calc(int i,int j)
    64 {
    65     return -(zb[i].y-zb[j].y)/(zb[i].x-zb[j].x);
    66 }
    67 inline int read()
    68 {
    69     int nn=0; char cc=getchar();
    70     while (cc<'0' || cc>'9') cc=getchar();
    71     while (cc>='0' && cc<='9') nn=(nn<<3)+(nn<<1)+(cc^48),cc=getchar();
    72     return nn;
    73 }
    大炮
  • 相关阅读:
    十月二十七学习报告
    十月二十六学习报告
    十月二十五学习报告
    十月二十四学习报告
    十月二十三学习报告
    十月二十二学习报告
    十月二十一学习报告
    十月十九学习报告
    十月十七学习报告
    十月十六学习报告
  • 原文地址:https://www.cnblogs.com/LH-Xuanluo/p/11684567.html
Copyright © 2020-2023  润新知