P3680 [CERC2016]凸輪廓線 Convex Contour 題解
阿新 • • 發佈:2021-07-25
差不多是凸包的板子題,十(fei)分(chang)的(du)水(liu)。。。
40pts做法:
將矩形的四點,三角形的三點,圓形的上下兩端各一點加入點陣,用 Andrew 演算法求凸包即可。
對於圓出現在佇列某一段的情況,要特別判斷。
100pts做法:
其實只需要將40pts做法做兩個改動即可:
-
1,將程式中的\(\pi\)設為3.141598653(這一步對步驟2至關重要);
-
2,仔細想想,題目中可能會出現 "CT" 或 "TC" 的情況。這時將三角形頂端與圓形頂端相連顯然不對。
該題的 \(n\leqslant20\) 使我們考慮使用最蠢的辦法:將圓上的數萬個點加入點陣。
即使不會三角函式(比如本蒟蒻
加入的點數不能太少,也不能太多。點太少會有精度誤差,太多可能會有幾個點TLE。
時間複雜度為 \(O(n log(n))\) 。
下面是我的原始碼:
#include <bits/stdc++.h> #define ll long long #define rgi register int using namespace std; const int M=1e7+7; inline int read(){ int w=0,r=1;char c=getchar(); while(!(isdigit(c)||c=='0'))c=getchar(); if(c=='-')r=-1,c=getchar(); while(isdigit(c))w=w*10+c-'0',c=getchar(); return w*r; } int n,m,used[M],stk[M],cnt; char c[M]; double pi=3.141592653,x,ans; struct pt{ double x,y; }p[M]; void add(double x,double y){ p[++m]=(pt){x,y}; } bool operator <(pt aa,pt bb){ return aa.x<bb.x||(aa.x==bb.x&&aa.y<bb.y); } pt operator -(pt aa,pt bb){ return (pt){aa.x-bb.x,aa.y-bb.y}; } double operator *(pt aa,pt bb){ return aa.x*bb.y*1.000000000-bb.x*aa.y*1.000000000; } double d(int x,int y){ return (double)sqrt(fabs(p[x].x-p[y].x)*fabs(p[x].x-p[y].x)*1.000000000+fabs(p[x].y-p[y].y)*fabs(p[x].y-p[y].y)*1.000000000); } int main(){ n=read(); scanf("%s",c+1); if(n==1){ if(c[1]=='C')printf("%f\n",pi); else if(c[1]=='S')printf("%f\n",4.000000000); else if(c[1]=='T')printf("%f\n",3.000000000); return 0; } for(int i=1;i<=n;i++,x+=1.000000000){ if(c[i]=='C'){ //if(i==1||i==n){ // ans=ans-1.000000000+pi/2.000000000; //} //add(x+0.500000000,0.000000000),add(x+0.500000000,1.000000000); for(double j=0.000000000;j<=1.000000000;j+=0.000100000){ double xx=sqrt(0.250000000-fabs(j-0.500000000)*fabs(j-0.500000000)),x1=x+0.500000000-xx,x2=x+0.500000000+xx; add(x1,j),add(x2,j); } }else if(c[i]=='S'){ add(x,0.000000000),add(x,1.000000000); add(x+1.000000000,0.000000000),add(x+1.000000000,1.000000000); }else{ add(x,0.000000000),add(x+1.000000000,0.000000000); add(x+0.500000000,(double)sqrt(0.750000000)); } } sort(p+1,p+m+1); stk[++cnt]=1; for(int i=2;i<=m;i++){ while(cnt>=2&&(p[stk[cnt]]-p[stk[cnt-1]])*(p[i]-p[stk[cnt]])<=0.000000)used[stk[cnt--]]=0; used[stk[++cnt]=i]=1; } int dn=cnt; for(int i=m-1;i;i--)if(!used[i]){ while(cnt>=2&&(p[stk[cnt]]-p[stk[cnt-1]])*(p[i]-p[stk[cnt]])<=0.000000)used[stk[cnt--]]=0; used[stk[++cnt]=i]=1; } for(int i=1;i<=cnt;i++){ int a=stk[i],b=stk[(i%cnt)+1]; ans+=d(a,b)*1.000000000; } printf("%.9lf\n",ans); return 0; } /* 4 TSTC */