Simpson积分裸题
P.S. 如何解决线段长度并:按左端点排序,然后记录当前右端点的最大值,扫一遍即可。
#include<iostream> #include<cstdlib> #include<cstring> #include<cmath> #include<cstdio> #include<algorithm> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define ull unsigned long long #define ld double #define maxn 1005 #define inf 1e9 #define eps 1e-7 using namespace std; int n,tot; bool tag[maxn]; struct circle{ld x,y,r;}a[maxn],b[maxn]; struct segment{ld l,r;}p[maxn]; inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline bool cmpc(circle a,circle b) { return a.r<b.r; } inline bool cmp(segment a,segment b) { return a.l==a.r?a.r<b.r:a.l<b.l; } inline ld get(ld x) { int cnt=0; F(i,1,n) if (fabs(x-a[i].x)<=a[i].r-eps) { ld tmp=sqrt(a[i].r*a[i].r-(x-a[i].x)*(x-a[i].x)); p[++cnt]=(segment){a[i].y-tmp,a[i].y+tmp}; } sort(p+1,p+cnt+1,cmp); ld h=-inf,ans=0; F(i,1,cnt) { if (h<p[i].l) ans+=p[i].r-p[i].l,h=p[i].r; else if (h<p[i].r) ans+=p[i].r-h,h=p[i].r; } return ans; } inline ld calc(ld l,ld r) { ld mid=(l+r)/2; return (get(l)/6+get(mid)*2/3+get(r)/6)*(r-l); } inline ld simpson(ld l,ld r) { ld mid=(l+r)/2,s1=calc(l,r),s2=calc(l,mid)+calc(mid,r); if (fabs(s2-s1)<=eps) return s2; else return simpson(l,mid)+simpson(mid,r); } int main() { n=read(); F(i,1,n) b[i].x=read(),b[i].y=read(),b[i].r=read(); sort(b+1,b+n+1,cmpc); F(i,1,n-1) F(j,i+1,n) if ((b[i].x-b[j].x)*(b[i].x-b[j].x)+(b[i].y-b[j].y)*(b[i].y-b[j].y)<=(b[i].r-b[j].r)*(b[i].r-b[j].r)) { tag[i]=true; break; } F(i,1,n) if (!tag[i]) a[++tot]=b[i]; n=tot; printf("%.3lf\n",simpson(-2000.0,2000.0)); return 0; }