这题调精度真痛苦啊(向管理员要了数据才调出来)。

用的是hwd在WC2015上讲的方法,考虑将原图分割,根据每个圆的左右边界和圆与圆交点的横坐标来分割,这样原图就被分成很多竖着的长条,并且每一条中间都没有交点,这样就有一个性质:每一条都是"弓形-梯形-弓形 弓形-梯形-弓形..."的形式,然后从一个方向开始,记录当前进入的圆的数量,每当出来就就计算面积。

 /**************************************************************
Problem: 2178
User: idy002
Language: C++
Result: Accepted
Time:1248 ms
Memory:48560 kb
****************************************************************/ #include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define eps 1e-11
#define N 2010
using namespace std; inline int sg( long double x ) { return (x>-eps)-(x<eps); }
struct Vector {
long double x, y;
Vector(){}
Vector( long double x, long double y ):x(x),y(y){}
Vector operator+( const Vector & b ) const { return Vector(x+b.x,y+b.y); }
Vector operator-( const Vector & b ) const { return Vector(x-b.x,y-b.y); }
Vector operator*( long double b ) const { return Vector(x*b,y*b); }
Vector operator/( long double b ) const { return Vector(x/b,y/b); }
long double operator^( const Vector & b ) const { return x*b.y-y*b.x; }
long double operator&( const Vector & b ) const { return x*b.x+y*b.y; }
long double ang() { return atan2(y,x); }
long double len() { return sqrt(x*x+y*y); }
long double len2() { return x*x+y*y; }
};
typedef Vector Point;
struct Circle {
Point c;
long double r;
Circle(){}
Circle( Point c, long double r ):c(c),r(r){}
inline bool in( Point &p ) {
Vector vv=p-c;
return (vv.x*vv.x+vv.y*vv.y) < r*r*0.999;
}
Point pt( long double ang ) const {
return c+Vector(cos(ang),sin(ang))*r;
}
};
struct Arc {
int cid, type;
long double al, ar;
Point pa, pb;
Arc(){}
Arc( int cid, int type, const Point &a, const Point &b );
long double area();
}; int n;
bool del[N], has[N];
long double spt[N*N]; int stot;
Circle cir[N];
Arc arc[N+N]; bool cmp_arc( const Arc &a, const Arc &b ) {
if( sg(a.pa.y-b.pa.y)!= ) return sg(a.pa.y-b.pa.y)<;
if( sg(a.pb.y-b.pb.y)!= ) return sg(a.pb.y-b.pb.y)<;
if( a.type!=b.type ) return a.type>b.type;
if( a.type== ) {
return cir[a.cid].r < cir[b.cid].r;
} else {
return cir[a.cid].r > cir[b.cid].r;
}
}
bool cmp_cir_r( const Circle &a, const Circle &b ) { return a.r<b.r; }
Arc::Arc( int cid, int type, const Point &a, const Point &b ) {
this->cid = cid;
this->type = type;
pa = a;
pb = b;
this->al = (a-cir[cid].c).ang();
this->ar = (b-cir[cid].c).ang();
if( pa.x>pb.x ) swap(pa,pb);
}
long double Arc::area() {
long double da = ar-al;
while( sg(da)<= ) da+=M_PI+M_PI;
while( sg(da-M_PI-M_PI)> ) da-=M_PI+M_PI;
return (da-sin(da))*cir[cid].r*cir[cid].r/2.0;
}
int ccinter( int ca, int cb, Point *p ) {
if( cir[ca].r<cir[cb].r ) swap(ca,cb);
long double cd = (cir[ca].c - cir[cb].c).len2();
long double s1 = cir[ca].r-cir[cb].r;
long double s2 = cir[ca].r+cir[cb].r;
s1=s1*s1, s2=s2*s2; if( sg(cd-s1)< || sg(cd-s2)> ) return ;
if( sg(cd-s1)== || sg(cd-s2)== ) {
long double ang = (cir[cb].c-cir[ca].c).ang();
p[] = cir[ca].pt(ang);
return ;
}
long double r1 = cir[ca].r, r2 = cir[cb].r;
long double base = (cir[cb].c-cir[ca].c).ang();
long double delta = acos( (r1*r1+cd-r2*r2)/(2.0*r1*sqrt(cd)) );
p[] = cir[ca].pt( base-delta );
p[] = cir[ca].pt( base+delta );
return ;
}
bool clinter( int c, long double xl, long double xr, Arc *arc ) {
long double xlb = cir[c].c.x-cir[c].r;
long double xrb = cir[c].c.x+cir[c].r;
if( sg(xlb-xr)>= || sg(xrb-xl)<= ) return false;
Point p = cir[c].c;
long double r = cir[c].r;
long double d1, d2;
long double s1 = r*r-(p.x-xl)*(p.x-xl);
long double s2 = r*r-(p.x-xr)*(p.x-xr);
if( s1<0.0 ) s1=0.0;
if( s2<0.0 ) s2=0.0;
d1 = sqrt( s1 );
d2 = sqrt( s2 );
arc[] = Arc( c, -, Point(xr,p.y+d2), Point(xl,p.y+d1) );
arc[] = Arc( c, +, Point(xl,p.y-d1), Point(xr,p.y-d2) );
return true;
}
long double area( long double lf, long double rg ) {
int m=;
for( int i=; i<n; i++ )
if( clinter(i,lf,rg,arc+m) )
m += ;
sort( arc, arc+m, cmp_arc ); int cc = , top;
long double rt = 0.0;
for( int i=; i<m; i++ ) {
if( cc== )
top = i;
cc += arc[i].type;
if( cc== ) {
rt += (rg-lf)*((arc[i].pa+arc[i].pb).y-(arc[top].pa+arc[top].pb).y)/2.0;
rt += arc[top].area()+arc[i].area();
}
}
return rt;
}
bool cmp_eq( long double x, long double y ) {
return sg(x-y)==;
}
void clean() {
int j=;
for( int i=; i<n; i++ )
if( !del[i] ) cir[j++]=cir[i];
n = j;
}
long double area() {
Point ip[];
int ic;
long double rt = 0.0;
for( int i=; i<n; i++ ) {
for( int j=i+; j<n; j++ ) {
ic = ccinter( i, j, ip );
if( ic<= ) continue;
for( int k=; k<ic; k++ ) {
int q=n;
for( q=; q<n; q++ ) {
if( q==i || q==j ) continue;
if( cir[q].in(ip[k]) )
break;
}
if( q==n ) spt[stot++]=ip[k].x;
}
}
}
for( int i=; i<n; i++ ) {
spt[stot++] = cir[i].c.x-cir[i].r;
spt[stot++] = cir[i].c.x+cir[i].r;
}
sort( spt, spt+stot );
stot = unique( spt, spt+stot, cmp_eq ) - spt; for( int i=; i<stot; i++ )
rt += area( spt[i-], spt[i] );
return rt;
}
void init() {
sort( cir, cir+n, cmp_cir_r );
for( int i=; i<n; i++ )
for( int j=i+; j<n; j++ ) {
long double dx = cir[i].c.x-cir[j].c.x;
long double dy = cir[i].c.y-cir[j].c.y;
long double dij = dx*dx+dy*dy;
long double cc = cir[j].r-cir[i].r;
cc = cc*cc;
if( dij<cc ) del[i]=true;
}
clean();
}
int main() {
scanf( "%d", &n );
for( int i=; i<n; i++ )
scanf( "%Lf%Lf%Lf", &cir[i].c.x, &cir[i].c.y, &cir[i].r );
init();
printf( "%.3Lf\n", area() );
}

bzoj 2178的更多相关文章

  1. [BZOJ 2178] 圆的面积并 【Simpson积分】

    题目链接:BZOJ - 2178 题目分析 用Simpson积分,将圆按照 x 坐标分成连续的一些段,分别用 Simpson 求. 注意:1)Eps要设成 1e-13  2)要去掉被其他圆包含的圆. ...

  2. BZOJ 2178: 圆的面积并 [辛普森积分 区间并]

    2178: 圆的面积并 Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 1740  Solved: 450[Submit][Status][Discus ...

  3. bzoj 2178 圆的面积并——辛普森积分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2178 把包含的圆去掉.横坐标不相交的一段一段圆分开算.算辛普森的时候预处理 f( ) ,比如 ...

  4. bzoj 2178 圆的面积并 —— 辛普森积分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2178 先看到这篇博客:https://www.cnblogs.com/heisenberg- ...

  5. bzoj 2178 自适应Simpson积分

    #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #i ...

  6. BZOJ 2178 圆的面积并 ——Simpson积分

    [题目分析] 史上最良心样例,史上最难调样例. Simpson积分硬上. 听说用long double 精度1e-10才能过. 但是double+1e-6居然过了. [代码] #include < ...

  7. bzoj 2178 圆的面积并【simpson积分】

    直接套simpson,f可以直接把圆排序后扫一遍所有圆,这样维护一个区间就可以避免空段. 然而一定要去掉被其他圆完全覆盖的圆,否则会TLE #include<iostream> #incl ...

  8. BZOJ 2178 Simpson积分

    思路: 我发现能用Simpson积分水的题  好像都是裸题诶233333 //By SiriusRen #include <bits/stdc++.h> using namespace s ...

  9. BZOJ 2178: 圆的面积并 (辛普森积分)

    code #include <set> #include <cmath> #include <cstdio> #include <cstring> #i ...

随机推荐

  1. ubuntu 18.04 安装 flash

    下载源码包, 解压 sudo cp Downloads/flash_player_npapi_linux.x86_64/libflashplayer.so /usr/lib/mozilla/plugi ...

  2. PATH变量重复

    命令: export PATH=$(echo $PATH | tr : "\n"| sort | uniq | tr "\n" :) Code: awk -F: ...

  3. 为什么我们不要.NET程序员(读后有点想法,所以转来了) 注:本文来自CSDN

    也许你已经知道了,我们正在招聘最优秀的程序员.不错,每个人都这样说.但是我们的程序员能打败你们的——任何时候.比如,米奇虽然只有5英尺高,但他是一个有相当实力的击剑手.维托尔德以前是一个6’3″的职业 ...

  4. python时序数据分析--以示例说明

    Python时间序列数据分析--以示例说明 标签(空格分隔): 时间序列数据分析 本文的内容主要来源于博客:本人做了适当的注释和补充. https://www.analyticsvidhya.com/ ...

  5. DevExpress GridControl 的数据绑定

    本人不才啊,折腾2个多小时才把数据绑定好.现在把折腾过程记录一下来以帮助更多的朋友,自己也温习一下. 直接上代码了哈.... WPF哈 xaml文件 <dxg:GridControl Name= ...

  6. Elasticsearch零停机时间更新索引配置或迁移索引

    本文介绍Elasticsearch零宕机时间更新索引配置映射内容的方法,包括字段类型.分词器.分片数等.方法原理就是,利用别名机制,给索引配置别名,所有应用程序都通过别名访问索引.重建索引,通过索引原 ...

  7. POJ 1141 Brackets Sequence(括号匹配二)

    题目链接:http://poj.org/problem?id=1141 题目大意:给你一串字符串,让你补全括号,要求补得括号最少,并输出补全后的结果. 解题思路: 开始想的是利用相邻子区间,即dp[i ...

  8. [USACO18FEB]Snow Boots S

    提供一种无脑DP做法 题目中大概有这么些东西:位置,穿鞋,跑路 数据小,那么暴力开数组暴力DP吧 设dp[i][j]表示穿着鞋子j,到达位置i是否可行 无脑转移 枚举位置,正在穿哪双鞋,换成哪双走出去 ...

  9. servlet 学习笔记(三)

    同一用户的不同页面共享数据有以下四种方法: 1.sendRedirect()跳转 2.session技术 3.隐藏表单提交(form) 4. cookie技术(小甜饼) --------------- ...

  10. CCF CSP 201604-2 俄罗斯方块

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201604-2 俄罗斯方块 问题描述 俄罗斯方块是俄罗斯人阿列克谢·帕基特诺夫发明的一款休闲游 ...