csp-s模拟75 导弹袭击

Posted lh-xuanluo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 #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 }
大炮

 

以上是关于csp-s模拟75 导弹袭击的主要内容,如果未能解决你的问题,请参考以下文章

AC日记——导弹拦截 洛谷 P1020 (dp+模拟)

模拟测试20191016

贪心4--拦截导弹

1112.拦截导弹(简单的动态规划)

C语言 拦截导弹

导弹拦截