UPD:這個作法被hack了node
題目大意:給你$n$個紅點和$m$個黑點,問你至少須要保留多少個黑點,才能用由黑點組成的凸包包住全部紅點。c++
數據範圍:$n≤10^5$,$m≤500$oop
首先,咱們將紅點和黑點丟到一塊兒,求一個凸包。凸包上的點能用黑點就用黑點,不然才用紅點。ui
全部重點,三點共線的點,都會被刪除。spa
若是求出的凸包上有紅點,那麼顯然是包不住的,直接輸出-1便可。code
咱們將在凸包上的黑點找出。blog
設$nxt[i]$表示凸包上第$i$號節點,能在順時針方向上刪除多少個凸包上的點,使得凸包依然能包含住所有的紅點。it
若是咱們求出了這個東西,咱們顯然能夠在$O(m)$的時間複雜度內,求出最少須要多少個點。class
考慮如何求$nxt[i]$hack
咱們對於由$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 }