题解

原来自适应simpson积分是个很简单的东西!

我们尝试分析一下影子,圆的投影还是圆,圆锥的尖投影成一个点,而圆台的棱是圆的公切线,我们把圆心投影出来,发现平面上圆心的距离是两两高度差/tan(alpha)

这是一个轴对称图形,我们只需要求一侧就好了

用simpson积分的公式

\(S = \frac{b - a}{6}(f(a) + 4 * f(\frac{a + b}{2}) + f(b))\)

计算区间就好了,啥,你说肯定不对……

确实肯定不对,然而你可以递归,如何判断这个区间计算的和正确答案相差无几呢,就是左右分别积分出来的值和整个区间的积分相差小于精度的时候就可以认为积分正确了,返回即可,否则左右递归计算积分

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <ctime>
//#define ivorysi
#define MAXN 505
#define eps 1e-7
#define pb push_back
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
inline db o(db x) {
return x * x;
}
bool dcmp(db a,db b) {
return fabs(a - b) <= eps;
}
struct Point {
db x,y;
Point(){}
Point(db _x,db _y) {
x = _x;y = _y;
}
friend Point operator + (const Point &a,const Point &b) {
return Point(a.x + b.x,a.y + b.y);
}
friend Point operator - (const Point &a,const Point &b) {
return Point(a.x - b.x,a.y - b.y);
}
friend Point operator * (const Point &a,const db &d) {
return Point(a.x * d,a.y * d);
}
friend db operator * (const Point &a,const Point &b) {
return a.x * b.y - a.y * b.x;
}
db norm() {
return sqrt(x * x + y * y);
}
friend db dot(const Point &a,const Point &b) {
return a.x * b.x + a.y * b.y;
}
}P[MAXN];
struct Seg {
Point a,b;
db d;
Seg(){}
Seg(Point _a,Point _b) {
a = _a;b = _b;
d = (b.y - a.y) / (b.x - a.x);
}
friend Point Cross_Point(const Seg &s,const Seg &t) {
db S1 = (s.a - t.a) * (t.b - t.a);
db S2 = (s.b - t.b) * (t.a - t.b);
return s.a + (s.b - s.a) * (S1 / (S1 + S2));
}
}S[MAXN];
db alpha;
db H[MAXN],R[MAXN];
int N;
db F(db x) {
db res = 0;
for(int i = 1 ; i <= N ; ++i) {
if(i != N) {
if(P[i + 1].x - P[i].x > fabs(R[i] - R[i + 1])) {
if(S[i].a.x + eps <= x && x <= S[i].b.x - eps) {
res = max(res,S[i].a.y + (x - S[i].a.x) * S[i].d);
}
}
}
if(x >= P[i].x - R[i] && x <= P[i].x + R[i]) {
res = max(res,sqrt(o(R[i]) - o(P[i].x - x)));
}
}
return res;
}
db calc(db L,db R) {
db mid = (L + R) / 2;
return (R - L) * (F(L) + F(R) + 4 * F((L + R) / 2)) / 6;
}
db Simpson(db L,db R) {
db mid = (L + R) / 2;
db Slr = calc(L,R),Sl = calc(L,mid),Sr = calc(mid,R);
if(dcmp(Slr,Sl + Sr)) return Sl + Sr;
else return Simpson(L,mid) + Simpson(mid,R);
}
void Init() {
scanf("%d%lf",&N,&alpha);
++N;
for(int i = N ; i >= 1; --i) scanf("%lf",&H[i]);
R[1] = 0;
for(int i = N ; i >= 2; --i) scanf("%lf",&R[i]);
for(int i = 1 ; i <= N ; ++i) H[i] /= tan(alpha);
P[1] = Point(0,0);
for(int i = 2 ; i <= N ; ++i) {
P[i] = Point(P[i - 1].x + H[i - 1],0);
}
}
void Solve() {
db r = 0,l = 0;
for(int i = 1 ; i <= N ; ++i) {
l = min(P[i].x - R[i],l);
r = max(r,P[i].x + R[i]);
}
for(int i = 1 ; i < N ; ++i) {
if(P[i + 1].x - P[i].x > fabs(R[i] - R[i + 1])) {
db C = (R[i] - R[i + 1]) / (P[i + 1].x - P[i].x);
db s1 = P[i].x + R[i] * C,s2 = P[i + 1].x + R[i + 1] * C;
db h1 = sqrt(o(R[i]) - o(P[i].x - s1)),h2 = sqrt(o(R[i + 1]) - o(P[i + 1].x - s2));
S[i] = Seg(Point(s1,h1),Point(s2,h2));
}
}
printf("%.2lf\n",Simpson(l,r) * 2);
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
}

【洛谷】P4207 [NOI2005]月下柠檬树的更多相关文章

  1. 洛谷P4207 [NOI2005]月下柠檬树(计算几何+自适应Simpson法)

    题面 传送门 题解 我还好奇自适应辛普森法干嘛用的呢--突然想起来积分的一个用处就是求曲边图形的面积-- 我们先来考虑一下这些投影是什么形状 一个圆的投影还是它自己 一个圆锥的投影是一个圆加上一个点, ...

  2. 5.21 省选模拟赛 luogu P4207 [NOI2005]月下柠檬树 解析几何 自适应辛普森积分法

    LINK:月下柠檬树 之前感觉这道题很鬼畜 实际上 也就想到辛普森积分后就很好做了. 辛普森积分法的式子不再赘述 网上多的是.值得一提的是 这道题利用辛普森积分法的话就是一个解析几何的问题 而并非计算 ...

  3. BZOJ 1502: [NOI2005]月下柠檬树 [辛普森积分 解析几何 圆]

    1502: [NOI2005]月下柠檬树 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1070  Solved: 596[Submit][Status] ...

  4. [NOI2005]月下柠檬树[计算几何(simpson)]

    1502: [NOI2005]月下柠檬树 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1169  Solved: 626[Submit][Status] ...

  5. 【BZOJ1502】[NOI2005]月下柠檬树 Simpson积分

    [BZOJ1502][NOI2005]月下柠檬树 Description 李哲非常非常喜欢柠檬树,特别是在静静的夜晚,当天空中有一弯明月温柔地照亮地面上的景物时,他必会悠闲地坐在他亲手植下的那棵柠檬树 ...

  6. [NOI2005]月下柠檬树

    题意 F.A.Qs Home Discuss ProblemSet Status Ranklist Contest 入门OJ ModifyUser  autoint Logout 捐赠本站 Probl ...

  7. BZOJ1502:[NOI2005]月下柠檬树——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=1502 https://www.luogu.org/problemnew/show/P4207 李哲 ...

  8. 1502: [NOI2005]月下柠檬树 - BZOJ

    Description Input 文件的第1行包含一个整数n和一个实数alpha,表示柠檬树的层数和月亮的光线与地面夹角(单位为弧度).第2行包含n+1个实数h0,h1,h2,…,hn,表示树离地的 ...

  9. [NOI2005]月下柠檬树(计算几何+积分)

    题目描述 李哲非常非常喜欢柠檬树,特别是在静静的夜晚,当天空中有一弯明月温柔 地照亮地面上的景物时,他必会悠闲地坐在他亲手植下的那棵柠檬树旁,独自思 索着人生的哲理. 李哲是一个喜爱思考的孩子,当他看 ...

随机推荐

  1. 转:UIView的sizeToFit与sizeThatFits

    UILabel经常用到的方法- (void)sizeToFit- (CGSize)sizeThatFits:(CGSize)size解释如下: sizeToFit会自动调用sizeThatFits方法 ...

  2. bzoj千题计划120:bzoj1032[JSOI2007]祖码Zuma

    http://www.lydsy.com/JudgeOnline/problem.php?id=1032 https://www.luogu.org/discuss/show?postid=8416 ...

  3. HDU 5446 lucas CRT

    n中选m个模M,M为多个素数之积 $n, m, k (1 \leq m \leq n \leq 10^{18}, 1 \leq k \leq 10)$,$M = p_1 · p_2 · · · p_k ...

  4. 华为mate 10 pro安装失败,提示没有未包含任何证书

    原因: Android 7.0 引入一项新的应用签名方案 APK Signature Scheme v2,它能提供更快的应用安装时间和更多针对未授权 APK 文件更改的保护.在默认情况下,Androi ...

  5. Writing your first academic paper

    Writing your first academic paper If you are working in academics (and you are if you are working wi ...

  6. Java并发编程原理与实战四十一:重排序 和 happens-before

    一.概念理解 首先我们先来了解一下什么是重排序:重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段. 从Java源代码到最终实际执行的指令序列,会分别经历下面3种重排序,如下图 ...

  7. 《编写高质量代码:改善JavaScript程序的188个建议》学习小记(二)

    建议3:减少全局变量污染 1.把多个全局变量都追加在一个名称空间下,将显著降低与其他应用程序产生冲突的概率,应用程序也会变得更容易阅读. var My = {}; My.name = { " ...

  8. ASP.NET项目与IE10、IE11不兼容的解决办法

    1.解决办法 机器级别修复, 服务器所有ASP.NET程序受益 需要去微软下载对应asp.NET版本的修补程序 .NET 4 -http://support.microsoft.com/kb/2600 ...

  9. Android 动态添加线性布局(.java文件内) 实现控件按比例分割空间

    这里实现 两个 编辑框同一水平上 按1:1分割空间 这里的1:1 比例可以通过 lp1.weight :  1p2.weight  =m:n 实现 { LinearLayout l=new Linea ...

  10. scrapy 爬虫踩过的坑(II)

    同事写了个爬虫,逻辑上看着没什么问题,但是一直报错:Request url must be str or unicode…… 打印了一下url 和url 的类型,确实是 unicode 懵逼…… 打印 ...