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 }