T1 bzoj: [Usaco2010 OPen]Triangle Counting 数三角形
看到这个题n那么大, 于是想到极角排序搞一搞,然而排完序后立马懵逼,完全不知道接下来应该怎么写。。。。
盯了好久题目给的图后全无思路于是手绘图,然后我就发现了秘密。。。。
极角排序后,如果两个点能与另外的某一个点构成黄金三角形,那么那个点必然在这两个点与原点连线的延长线所夹的区间内。
又因为有极角排序,点a[1],a[2]能构成的三角形,换成点a[1],a[3]肯定也可以构成,因为它们的区间一定是包含关系。
于是我们搞出所有a[i],a[i-1]区间内的答案,计算对答案的贡献即可。
正着有i-1个区间包含它,反着有n-i个区间包含它,然后搞一搞就好了。。。
细节什么的参见代码,反正感觉我代码是写丑了,我还算出了j搞了两遍for循环,看他们代码一个个巨短。。。。理应一遍就应该可以了吧。。。。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 #define maxn 100100 8 #define pi (acos(-1.0)) 9 10 int n,j,tmp,sum; 11 long long ans; 12 13 struct point{ 14 double x,y,ang; 15 }p[maxn]; 16 17 double operator *(point a,point b){return a.x*b.y-a.y*b.x;} 18 19 bool cmp(point a,point b){ 20 return a.ang<b.ang; 21 } 22 23 int main(){ 24 // freopen("input.txt","r",stdin); 25 // freopen("output.txt","w",stdout); 26 scanf("%d",&n); 27 for (int i=1;i<=n;i++) 28 scanf("%lf%lf",&p[i].x,&p[i].y),p[i].ang=atan2(p[i].y,p[i].x); 29 sort(p+1,p+n+1,cmp); 30 for (int i=1;i<=n;i++) if (p[i].ang-p[1].ang>pi){j=tmp=i;break;} 31 for (int i=2;i<j;i++){ 32 int sum=0; 33 while (p[tmp].ang-p[i].ang<pi && tmp<=n) tmp++,sum++; 34 ans+=(long long)sum*(i-1)*(j-i); 35 } 36 for (int i=1;i<j;i++) if (p[j].ang-p[i].ang<pi){tmp=i;break;} 37 for (int i=j+1;i<=n;i++){ 38 int sum=0; 39 while (p[i].ang-p[tmp].ang>pi && tmp<j) tmp++,sum++; 40 ans+=(long long)sum*(i-j)*(n-i+1); 41 } 42 printf("%lld\n",ans); 43 return 0; 44 }
T1
T2 poj 3608 Bridge Across Islands
两个多边形间的旋转卡壳,网上给了一大堆代码,一大堆题解,感觉都大同小异,几乎都是国外某大牛的论文翻译过来的。。。。。什么搞出一个ymin,ymax,特别是哪个叉乘while,根本看不懂。。。。。线段之间的距离真的可以用叉乘吗。。。。。(蒟蒻求解。。。)
于是我有一种想法,首先在多边形P上随便找到一条边,然后找到多边形Q上距离最近的点,然后将多边形P上的该边跳到它的邻边,同时直接移动多边形Q上找到的点,和两边的点比较,之后移动,直到移动到下一个点的距离比该点距离大就停止。然后在多边形Q上也做一次类似的即可。然后每次移动更新答案,就完了。。。。。
感觉这样做正确性也十分显然,因为对于任意一条边,另一个多边形的所有点距离它都是单峰的。于是对于当前点,它一定能找到距离最近的点。注意这里并不用两个指针扫,只需要将当前点与左右两边比较就行了。因为不可能出现左右两边的点都比当前点更优的情况,因为当前点一定是左右两边的某个点转移过来的,而对于当前的边,它一定会比至少一条边优。(这个性质稍微分情况讨论一下也可以得出),同时因为边每次只是跳到邻边,因此绝对不会出现每次移动n/2的情况,因为这个过程类似于旋转卡壳实现过程,时间复杂度也是可以保证的,常数好像大了一些。。。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 #define maxn 100010 8 #define inf 1e9 9 10 int n,m; 11 double ans; 12 13 struct point{ 14 double x,y; 15 }p[maxn],q[maxn]; 16 17 struct line{ 18 point from,to; 19 }lp[maxn],lq[maxn]; 20 21 point operator -(point a,point b){return (point){a.x-b.x,a.y-b.y};} 22 double operator *(point a,point b){return a.x*b.y-a.y*b.x;} 23 24 double sqr(double x){return x*x;} 25 double dis(point a,point b){return sqr(a.x-b.x)+sqr(a.y-b.y);} 26 27 double point_line_dis(point a,line b){ 28 if (dis(b.to,b.from)+min(dis(a,b.to),dis(a,b.from))<max(dis(a,b.to),dis(a,b.from))) 29 return sqrt(min(dis(a,b.to),dis(a,b.from))); 30 else return fabs((b.to-a)*(b.from-a))/sqrt(dis(b.to,b.from)); 31 } 32 33 void solvep(){ 34 double dist=inf;int pos; 35 for (int i=1;i<=m;i++){ 36 double tmp=point_line_dis(q[i],lp[1]); 37 if (tmp<dist) 38 dist=tmp,pos=i; 39 } 40 ans=min(ans,dist); 41 for (int i=2;i<=n;i++){ 42 while (point_line_dis(q[pos],lp[i])>point_line_dis(q[pos+1],lp[i])) pos==m?pos=1:pos++; 43 while (point_line_dis(q[pos],lp[i])>point_line_dis(q[pos-1],lp[i])) pos==1?pos=m:pos--; 44 ans=min(ans,point_line_dis(q[pos],lp[i])); 45 } 46 } 47 48 void solveq(){ 49 double dist=inf;int pos; 50 for (int i=1;i<=n;i++){ 51 double tmp=point_line_dis(p[i],lq[1]); 52 if (tmp<dist) 53 dist=tmp,pos=i; 54 } 55 ans=min(ans,dist); 56 for (int i=2;i<=m;i++){ 57 while (point_line_dis(p[pos],lq[i])>point_line_dis(p[pos+1],lq[i])) pos==n?pos=1:pos++; 58 while (point_line_dis(p[pos],lq[i])>point_line_dis(p[pos-1],lq[i])) pos==1?pos=n:pos--; 59 ans=min(ans,point_line_dis(p[pos],lq[i])); 60 } 61 } 62 63 int main(){ 64 while (scanf("%d%d",&n,&m)!=EOF){ 65 ans=inf; 66 if (n==0 && m==0) break; 67 for (int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); 68 for (int i=1;i<=m;i++) scanf("%lf%lf",&q[i].x,&q[i].y); 69 p[n+1]=p[1],q[m+1]=q[1]; 70 for (int i=1;i<=n;i++) lp[i].from=p[i],lp[i].to=p[i+1]; 71 for (int i=1;i<=m;i++) lq[i].from=q[i],lq[i].to=q[i+1]; 72 solvep(); 73 solveq(); 74 printf("%.6f\n",ans); 75 } 76 return 0; 77 }