【xsy2305】喽 计算几何
UPD:这个做法被hack了
题目大意:给你$n$个红点和$m$个黑点,问你至少需要保留多少个黑点,才能用由黑点组成的凸包包住所有红点。
数据范围:$n≤10^5$,$m≤500$
首先,我们将红点和黑点丢到一起,求一个凸包。凸包上的点能用黑点就用黑点,否则才用红点。
所有重点,三点共线的点,都会被删除。
如果求出的凸包上有红点,那么显然是包不住的,直接输出-1即可。
我们将在凸包上的黑点找出。
设$nxt[i]$表示凸包上第$i$号节点,能在顺时针方向上删除多少个凸包上的点,使得凸包依然能包含住全部的红点。
如果我们求出了这个东西,我们显然可以在$O(m)$的时间复杂度内,求出最少需要多少个点。
考虑如何求$nxt[i]$
我们对于由$i$和$i+nxt[i]$构成的连线,如果是合法的,那么显然要满足凸包外侧没有任何点。
我们可以对所有红点,都用叉积判一遍就可以了。
更新$nxt[i]$的过程可以用类似旋转卡壳的方式来搞,单次均摊是$O(n)$的。
(我场上$sb$了居然在求凸包,虽然也可以判,但是它T了)
这么搞时间复杂度是$O(nm)$的,实际上跑得飞快。
时间复杂度为$O((n+m)\log\ (n+m)+nm)$
1 #include<bits/stdc++.h> 2 #define L long long 3 #define M 110000 4 #define INF 19890604 5 using namespace std; 6 7 struct node{ 8 L x,y;int type; 9 void rd(int Type){type=Type; scanf("%lld%lld",&x,&y);} 10 node(){x=y=type=0;} 11 node(L X,L Y,int Type){x=X; y=Y; type=Type;} 12 friend node operator +(node a,node b){return node(a.x+b.x,a.y+b.y,0);} 13 friend node operator -(node a,node b){return node(a.x-b.x,a.y-b.y,0);} 14 friend L operator *(node a,node b){return a.x*b.y-a.y*b.x;} 15 friend bool operator ==(node a,node b){return a.x==b.x&&a.y==b.y;} 16 }a[M],s[M],b[505],all[M],bas=node(0,1e9,0); 17 int n,m,cnt=0,nm=0; 18 19 bool cmp(node x,node y){ 20 if(x.x==y.x&&x.y==y.y) return x.type<y.type; 21 return (x-bas)*(y-bas)>0; 22 } 23 void build(){ 24 for(int i=1;i<=nm;i++) if(all[1].y>all[i].y) swap(all[1],all[i]); 25 bas=all[1]; sort(all+2,all+nm+1,cmp); 26 for(int i=1;i<=nm;i++){ 27 while(cnt>1&&(s[cnt]-s[cnt-1])*(all[i]-s[cnt-1])<=0) 28 cnt--; 29 if(cnt>0&&s[cnt]==all[i]) cnt--; 30 s[++cnt]=all[i]; 31 } 32 } 33 int nxt[M]={0},vis[M]={0}; 34 int dfs(int x,int dep){ 35 if(vis[x]) return printf("%d\n",dep-vis[x]); 36 vis[x]=dep; 37 dfs(nxt[x],dep+1); 38 } 39 40 int main(){ 41 scanf("%d%d",&n,&m); 42 for(int i=1;i<=n;i++) a[i].rd(1),all[++nm]=a[i]; 43 for(int i=1;i<=m;i++) b[i].rd(2),all[++nm]=b[i]; 44 build(); 45 for(int i=1;i<=cnt;i++) if(s[i].type==1) return printf("-1\n"); 46 if(cnt==1) return printf("1\n"); 47 memset(b,0,sizeof(b)); m=cnt; 48 for(int i=1;i<=m;i++) b[i]=b[i+cnt]=s[i]; 49 for(int i=1,j=1;i<=m;i++){ 50 while(1){ 51 if(j==i) j++; 52 for(int k=1;k<=n;k++) 53 if((a[k]-b[i])*(b[j]-b[i])>0) 54 goto loop; 55 j++; 56 } 57 loop:; 58 nxt[i]=(j-2+m)%m+1; 59 } 60 dfs(1,1); 61 }