[CERC2016]:凸轮廓线Convex Contour(模拟+数学)

题目描述

一些几何图形整齐地在一个网格图上从左往右排成一列。它们占据了连续的一段横行,每个位置恰好一个几何图形。每个图形是以下的三种之一:
$1.$一个恰好充满单个格子的正方形。
$2.$一个内切于单个格子的圆。
$3.$一个底边与格子重合的等边三角形。

已知每个格子的边长都为$1$,请求出这些几何图形的凸包的周长。


输入格式

第一行包含一个正整数$n$,表示几何图形的个数。
第二行包含$n$个字符,从左往右依次表示每个图形,$"S"$表示正方形,$"C"$表示圆形,$"T"$表示等边三角形。


输出格式

输出一行一个实数,即凸包的周长。与答案的绝对或相对误差不超过$10^{-6}$时被认为是正确的。


样例

样例输入:

4
TSTC

样例输出:

9.088434417



数据范围与提示

$1\leqslant n\leqslant 20$


题解

突然看到自己刚学$OI$时的题解,已经是一年前的题解了(有同学说,一年前的我都能掉打现在的他),那是满是美好的回忆,没有现在临近$CSP-S$痛苦的日常。

附上一年前的题解链接:题解 P3680 【[CERC2016]凸轮廓线 Convex Contour】

上面这篇题解中有错误(还是当时菜),评论区已经有人指正了,在此不再赘述。

这天又打了一遍,在原来的基础上讲一讲自己现在对这道题的心得和体会。

不知道为什么数据范围是$20$,总之我的时间复杂度是$\Theta(n)$的……

显然中间无论是什么形状都是无所谓的,因为无论是什么图形

先来考虑正方形和圆形在两端的情况,这样会简单很多,因为它们的高度都是$1$,这样我们无非就是需要考虑两头是什么形状就好了:

  $\alpha.$如果两头都是正方形,那么答案就是$2\times n+2\downarrow$

  

  $\beta.$如果是一个正方形,一个圆形,答案就是$2\times n+\dfrac{\frac{\sqrt{3}}{2}\pi}{2}$

  

  $\gamma.$如果两头都是圆形,那么答案就是$2\times n-2+\pi\downarrow$

  

再来考虑三角形在两端的情况,远没有你想象的简单。

你以为是这样的:

然而是事实这样的:

于是你就弃掉了它……

如果你还能看到这里,就说明你还有希望,那么我们先来考虑三角形在一头,下一个是正方形的情况:

你以为是这样:

然而事实又是这样:

难点在于处理“悬空”的那条线的长度,但是我们发现了如下的一个直角三角形:

可以先求出来这个直角三角形的两个直角边的长度再通过勾股定理求出斜边长,不妨对这个直角三角形作出如下定义:

因为边长为$1$的等边三角形的高为$\frac{sqrt{3}}{2}$,所以我们可以知道$a=1-\frac{sqrt{3}}{2}$,$b$很好求,就是开头三角形的个数$-0.5$。

三角形在最后同理,在此不再赘述。

于是我们解决了三角形$+$正方形的情况。

考虑最后的也是最难的三角形$+$圆形的情况:

你以为是这样的:

然而事实又是这样:

上图中粗的红线是圆的切线,那么我们又可以找到一个三角形:

不妨再做出如下定义:

$a$就是圆形边长,很好求,难点变成了求$b$。

再回到上一张图,又发现了一个三角形:

再放大这个三角形:

$d$就是$\sqrt{3}-1$,$e$则是开头三角形的个数,于是我们可以得到$b$。

所有情况枚举完了,这道题也就轻松解决了。

时间复杂度:$\Theta(n)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
char ch[20];
double ans,p;
int n,flag;
int main()
{
	scanf("%d%s",&n,ch+1);
	ans+=n-1;
	if(ch[1]==‘C‘)flag=2,ans+=M_PI/2;
	if(ch[n]==‘C‘)ans+=M_PI/2;
	if(ch[1]==‘T‘)p+=1.0,flag=0,ans+=1.5;
	if(ch[n]==‘T‘)ans+=1.5;
	if(ch[1]==‘S‘)flag=1,ans+=2.5;
	if(ch[n]==‘S‘)ans+=1.5;
	for(int i=2;i<=n;i++)
		switch(ch[i])
		{
			case ‘T‘:p+=1.0;break;
			case ‘S‘:
				switch(flag)
				{
					case 0:
						ans+=sqrt((p-0.5)*(p-0.5)+(7.0/4.0-sqrt(3)))+1.0;
						p=0;
						flag=1;
					break;
					case 1:
						ans+=p+1.0;
						p=0;
					break;
					case 2:
						ans+=p+1.5;
						p=0;
						flag=1;
					break;
				}
			break;
			case ‘C‘:
				switch(flag)
				{
					case 0:
					{
						double x=1.0*(p);
						double y=(sqrt(3)/2.0-0.5);
						double z=sqrt(x*x+1.0-sqrt(3)/2.0);
						double len1=sqrt(x*x+1.0-sqrt(3)/2.0-0.25);
						double o=M_PI/2.0-atan(y/x)-acos(0.5/z);
						double len2=0.5*o;
						p=0;
						ans+=len1+len2;
						flag=2;
					}
					break;
					case 1:
						ans+=p+0.5;
						p=0;
						flag=2;
					break;
					case 2:
						ans+=p+1.0;
						p=0;
					break;
				}
			break;
		}
	if(p)
		switch(flag)
		{
			case 0:ans+=p-1.0;break;
			case 1:ans+=sqrt((p-0.5)*(p-0.5)+(7.0/4.0-sqrt(3)));break;
			case 2:
			{
				double x=1.0*(p);
				double y=(sqrt(3)/2.0-0.5);
				double z=sqrt(x*x+1.0-sqrt(3)/2.0);
				double len1=sqrt(x*x+1.0-sqrt(3)/2.0-0.25);
				double o=M_PI/2.0-atan(y/x)-acos(0.5/z);
				double len2=0.5*o;
				ans+=len1+len2;
			}
			break;
		}
	printf("%.9lf",ans);
	return 0;
}


rp++

原文地址:https://www.cnblogs.com/wzc521/p/11690606.html

时间: 2024-12-31 16:12:20

[CERC2016]:凸轮廓线Convex Contour(模拟+数学)的相关文章

SRM11 T1 骰子 (模拟--&gt;数学)

题目大意:一个骰子在有R*C格的矩形地图上从第一行第一格开始滚来滚去,滚完一行后以相反方向滚下一行,滚完所有格子后停.求所有时刻骰子上方的点数和. O(RC)做法:模拟.用u,f,r分别记录骰子上.前.右三面的点数. 向左滚:int d=7-u:u=r:r=d;//骰子相对面上点数和为7,d暂存底面点数,滚动后原来的右面跑到上面,底面跑到右面. 向右滚:int l=7-r:r=u; u=l;//l暂存左面点数 向下滚:int b=7-f:f=u; u=b;//b暂存后面点数 O(1)做法:数学(

数字整除(南阳oj664)(模拟数学)

数字整除 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描述 定理:把一个至少两位的正整数的个位数字去掉,再从余下的数中减去个位数的5倍.当且仅当差是17的倍数时,原数也是17的倍数 . 例如,34是17的倍数,因为3-20=-17是17的倍数:201不是17的倍数,因为20-5=15不是17的倍数.输入一个正整数n,你的任务是判断它是否是17的倍数. 输入 输入文件最多包含10组测试数据,每个数据占一行,仅包含一个正整数n(1<=n<=10^100),表示待判断的正

【计算几何】【分类讨论】Gym - 101173C - Convex Contour

注意等边三角形的上顶点是卡不到边界上的. 于是整个凸包分成三部分:左边的连续的三角形.中间的.右边的连续的三角形. 套个计算几何板子求个三角形顶点到圆的切线.三角形顶点到正方形左上角距离啥的就行了,分类比较多. #include<cstdio> #include<cmath> using namespace std; const double PI=acos(-1.0); int n; char a[25]; struct Point{ double x,y; double len

Codeforces 101173 C - Convex Contour

思路: 如果所有的图形都是三角形,那么答案是2*n+1 否则轮廓肯定触到了最上面,要使轮廓线最短,那么轮廓肯定是中间一段平的 我们考虑先将轮廓线赋为2*n+2,然后删去左右两边多余的部分 如果最左边或最由边是正方形,那么不需要删 如果最左边或最由边是圆形,那么删取2 - pi/2 如果如果最左边或最由边是三角形,那么我们需要找到一段连续的三角形,然后考虑怎么删去 #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimiz

[CSP-S模拟测试]:炼金术士的疑惑(模拟+数学+高斯消元)

题目传送门(内部题70) 输入格式 第一行一个正整数$n$,表示炼金术士已知的热化学方程式数量.接下来$n$行,每行一个炼金术士已知的热化学方程式.最后一行一个炼金术士想要求解的热化学方程式,末尾记为$H=?$.每个热化学方程式都是规范的,格式如下:$a\ W\ +\ b\ X\ +\ ...\ =\ c\ Y\ +\ d\ Z\ ...\ H=\ h$表示$a$单位的$W$.$b$单位的$X$与......反应生成了$c$单位的$Y$.$d$单位的$Z$和......,吸收$h$/放出$-h$

函数式编程语言

最近一段时间总是听到或者看到有人谈论“函数式编程”,第一次接触是在大概半年前的一次沙龙中,当时听人讲的时候,心想这有什么难理解的,函数式编程,函数嘛,那就是C呀,C++放在首位的是对象,面向对象编程,C放在首位的不是函数吗,那就是函数式编程啊,整个经验交流迷迷糊糊的,只记住了个lambda.但是在后来陆陆续续还是听到了这个名词,而且也知道并不是我理解的那个样子,C不是“函数式编程”,而是“面向过程编程”,是“命令式编程”,但是还不是很理解到底是怎么区分的.于是周末翻阅了一下资料,稍作“概念层次”

转:python 的开源库

Python在科学计算领域,有两个重要的扩展模块:Numpy和Scipy.其中Numpy是一个用python实现的科学计算包.包括: 一个强大的N维数组对象Array: 比较成熟的(广播)函数库: 用于整合C/C++和Fortran代码的工具包: 实用的线性代数.傅里叶变换和随机数生成函数. SciPy是一个开源的Python算法库和数学工具包,SciPy包含的模块有最优化.线性代数.积分.插值.特殊函数.快速傅里叶变换.信号处理和图像处理.常微分方程求解和其他科学与工程中常用的计算.其功能与软

每日一练第5天:分数化小数

输入正整数a,b,c,输出a/b的小数形式,精确到小数点后c位.a,b≤10 6 ,c≤100.输入包含多组数据, 结束标记为a=b=c=0. 样例输入: 1 6 4 0 0 0 样例输出: Case 1: 0.1667 这道题靠计算机本身来做除法是会出现精度问题的,所以要模拟数学上的除法: 1 #include <stdio.h> 2 3 int main() 4 { 5 int a, b, c, ct = 1; 6 while(3 == scanf("%d%d%d",

【冒号课堂】【阅读笔记】编程范式整理

编程范式 命令式/过程式(Imperative/Procedural) 代表语言 Fortran/Pascal/C 核心概念 命令/过程(Command/Procedure) 运行机制 命令执行 关键突破 突破单一主程序和非结构话程序的限制 实现原理 引入逻辑控制与子程序 主要目的 模拟机器思维,实现自顶向下的模块设计 常见应用 交互式.事件驱动型系统.数值计算等 编程范式 函数式/应用式(Functional/Applicative) 代表语言 Scheme/Haskell 核心概念 函数(F