给你一个圆,圆心在原点,每次有一条直线,切掉圆中不包含原点的部分。
(直线给出的部分是它在于圆两个交点形成的线段的垂直平分线跟 x 正半轴的角度和这条直线跟垂直平分线交点到源点的距离)
然后最后问你剩下的那个图形圆弧部分的长度和与直线部分的长度和。
切割蛋糕
题目大意
给你一个圆,圆心在原点,每次有一条直线,切掉圆中不包含原点的部分。
(直线给出的部分是它在于圆两个交点形成的线段的垂直平分线跟 x 正半轴的角度和这条直线跟垂直平分线交点到源点的距离)
然后最后问你剩下的那个图形圆弧部分的长度和与直线部分的长度和。
思路
不难想到可以直接上半平面交然后随便做(圆拆成很多条直线就行)
但我半平面写挂了,用一个别的好写写法。
首先你可以算出每条直线它与圆的两个交点,分别在圆上的角度。
那我们可以算出没有被切去的圆弧的长度了。
然后至于算直线,我可以枚举每一个直线,看它被保留了多少。
(一开始是它跟圆两个交点的距离)
那看保留我们就枚举别的直线,找到交点分别属于这个直线的两边的,然后算两个直线的交点,更改保留的部分。
不难想到保留的部分一定是一个区间,因为每次保留(或者删去)的部分都是一个你直线的一个前缀或者后缀。
那把每个直线保留的长度加上就是直线的答案了。
代码
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 55;
const double Pi = acos(-1.0);
struct dian {
double x, y;
}a[N], b[N];
int n, m, l[N], r[N];
double RR, L[N], R[N], p[N], val[N];
bool in[N], no[N];
dian operator +(dian x, dian y) {
return (dian){x.x + y.x, x.y + y.y};
}
dian operator -(dian x, dian y) {
return (dian){x.x - y.x, x.y - y.y};
}
dian operator *(dian x, double y) {
return (dian){x.x * y, x.y * y};
}
double operator *(dian x, dian y) {
return x.x * y.x + x.y * y.y;
}
double operator ^(dian x, dian y) {
return x.x * y.y - x.y * y.x;
}
struct line {
dian x, y;
};
dian Meet(line a, line b) {
double k = ((b.y - b.x) ^ (a.x - b.x)) / ((a.y - a.x) ^ (b.y - b.x));
return a.x + (a.y - a.x) * k;
}
dian Meet(dian ax, dian ay, dian bx, dian by) {
double k = ((by - bx) ^ (ax - bx)) / ((ay - ax) ^ (by - bx));
return ax + (ay - ax) * k;
}
double dis(dian x, dian y) {
return sqrt((x.x - y.x) * (x.x - y.x) + (x.y - y.y) * (x.y - y.y));
}
int main() {
freopen("cake.in", "r", stdin);
freopen("cake.out", "w", stdout);
scanf("%d %lf", &n, &RR);
for (int i = 1; i <= n; i++) {
double A, h; scanf("%lf %lf", &A, &h);
A = A / 180 * Pi; double B = acos(h / RR);
L[i] = A - B; R[i] = A + B;
while (L[i] < 0) L[i] += 2 * Pi;
while (R[i] >= 2 * Pi) R[i] -= 2 * Pi;
p[++m] = L[i]; p[++m] = R[i];
a[i] = (dian){cos(L[i]), sin(L[i])};
b[i] = (dian){cos(R[i]), sin(R[i])};
}
sort(p + 1, p + m + 1); m = unique(p + 1, p + m + 1) - p - 1;
double ans1 = 0, ans2 = 2 * Pi;
for (int i = 1; i <= n; i++) {
l[i] = lower_bound(p + 1, p + m + 1, L[i]) - p;
r[i] = lower_bound(p + 1, p + m + 1, R[i]) - p;
for (int j = l[i]; j != r[i]; j = j % m + 1) {
if (in[j]) continue; in[j] = 1;
double x = p[j % m + 1] - p[j];
while (x < 0) x += 2 * Pi;
ans2 -= x;
}
}
for (int i = 1; i <= m; i++) in[i] = 0;
for (int i = 1; i <= n; i++) {
for (int j = l[i]; j != r[i]; j = j % m + 1) in[j] = 1;
double ls = 0, rs = dis(a[i], b[i]);
for (int j = 1; j <= n; j++) {
if (i == j) continue;
if (!in[l[j]] && !in[r[j]]) continue;
if (in[l[j]] && in[r[j]]) {
no[j] = 1; continue;
}
double awa = dis(Meet(a[i], b[i], a[j], b[j]), a[i]);
if (in[l[j]]) rs = min(rs, awa);
else ls = max(ls, awa);
}
if (ls <= rs) val[i] = rs - ls;
for (int j = l[i]; j != r[i]; j = j % m + 1) in[j] = 0;
}
for (int i = 1; i <= n; i++) {
if (no[i]) continue;
ans1 += val[i];
}
printf("%.10lf %.10lf", ans1 * RR, ans2 * RR);
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
2022-02-24 【2022 省选训练赛 Contest 05 C】B(计算几何)
2022-02-24 【2022 省选训练赛 Contest 05 B】卷积练习题(暴力)(性质)
2022-02-24 【2022 省选训练赛 Contest 05 A】tree(树形DP)
2021-02-24 【ybt金牌导航6-5-1】【luogu P3810】【模板】三维偏序(陌上花开)
2021-02-24 【ybt金牌导航6-4-1】区间不同数 / 莫队例题
2021-02-24 【ybt金牌导航6-3-1】【luogu P4168】区间众数 / 蒲公英 / 分块例题
2021-02-24 【ybt金牌导航6-2-1】【luogu P3201】梦幻布丁 / 启发式合并例题