一、题目解读
1、原题
2、分类
杂题
3、题意
求[连续运动的]时钟、在 1 1 1天内满足条件“任意两个指针夹角大于角度 D D D”的总时间占 1 1 1天的百分比。
4、输入输出格式
输入/输出 | 要求与格式 |
---|---|
输入样例个数 | 通过输入 D = − 1 D=-1 D=−1标识输入结束 |
输入格式(每个样例) | 每行输入一个数 D D D |
输出格式(每个样例) | 每行输出一个结果 |
输出精度 | 结果精确到小数点后三位 |
5、数据范围
数据 | 范围 |
---|---|
D D D | 0 ≤ D ≤ 120 , D ∈ R 0 \leq D \leq 120, D \in \mathbb{R} 0≤D≤120,D∈R |
二、题解参考
1、总体思路
思路 | 时间复杂度 | 具体解释 |
---|---|---|
穷举时分,累加秒长 | O ( 1 ) O(1) O(1)(每个案例将近 1 0 4 10^4 104次语句执行) | 穷举12个h、60个m,在每组确定的(h, m)下的 1 m i n 1min 1min内,找出满足题意的可行区间 |
2、思路①
(1).分析
很显然,时钟表面上只会显示12个小时,因此一天中我们也只需要考虑半天。
给定 h h h(时)、 m m m(分)、 s s s(秒),不难得出三者对应指针以12点方向为起点的角度 { d e g _ h = 30 h + 1 2 m + 1 120 s d e g _ m = 6 m + 1 10 s d e g _ s = 6 s \begin{cases} deg\_h = 30h + \frac{1}{2}m + \frac{1}{120}s \\ deg\_m = 6m + \frac{1}{10}s \\ deg\_s = 6s \end{cases} ⎩⎪⎨⎪⎧deg_h=30h+21m+1201sdeg_m=6m+101sdeg_s=6s
由此,很容易得出三个角度差 { Δ h m = 30 h + ( 1 2 − 6 ) m + ( 1 120 − 1 10 ) s Δ h s = 30 h + 1 2 m + ( 1 120 − 6 ) s Δ m s = 6 m + ( 1 10 − 6 ) s \begin{cases} \Delta hm = 30h + (\frac{1}{2} - 6)m + (\frac{1}{120} - \frac{1}{10})s \\ \Delta hs = 30h + \frac{1}{2}m + (\frac{1}{120} - 6)s \\ \Delta ms = 6m + (\frac{1}{10} - 6)s \end{cases} ⎩⎪⎨⎪⎧Δhm=30h+(21−6)m+(1201−101)sΔhs=30h+21m+(1201−6)sΔms=6m+(101−6)s
根据题目的要求、加上我们最开始的简化,我们需要找到半天之内所有满足以下条件的时间段: { D ≤ ∣ Δ h m ∣ ≤ 360 − D D ≤ ∣ Δ h s ∣ ≤ 360 − D D ≤ ∣ Δ m s ∣ ≤ 360 − D \begin{cases} D \leq | \Delta hm | \leq 360 - D \\ D \leq | \Delta hs | \leq 360 - D \\ D \leq | \Delta ms | \leq 360 - D \end{cases} ⎩⎪⎨⎪⎧D≤∣Δhm∣≤360−DD≤∣Δhs∣≤360−DD≤∣Δms∣≤360−D
秒针每一分钟就会转动一圈,显然 Δ h s \Delta hs Δhs和 Δ m s \Delta ms Δms都会在 0 ∼ 360 0 \sim 360 0∼360之间快速变化,所以满足题述角度的临界时间会特别多,因此想要直接根据角度、寻找某个公式来求出所有的临界情况是几乎不可能的。
考虑到时钟的指针是连续运动的,因此无法穷举所有时、分、秒。但是仔细思考一下,可以知道,虽然秒不可以穷举,但是时、分还是可以穷举的,只要把时、分确定了,这一分钟内秒的范围也就很容易求出来了(只需要解线性不等式组)。
对于每个不等式,我们一般可以求出两组区间,然后求并集。再把每一个不等式的解求一个交集,就可以知道总体的解区间了。虽然这样做逻辑上很合理,但是要实现却不容易,因为并集并出来的可能是空集,可能是单个连续区间,也可能是多个连续子区间。这样的区间概念不方便实现。
于是我们想到了一个办法进行优化——将三个不等式视为三个组,每组有两个区间解,只要将每组中选一个出来,求出三个区间的交集,遍历所有组合,将时间累积起来即可。
(2).AC代码
HDU(C++/G++)AC代码如下:
#include <iostream>
#include <iomanip>
#include <algorithm>
using namespace std;
double D;
struct interval
{
double l;
double r;
};
// 计算满足线性不等式组【D <= as + b <= 360-D】s的解区间,并且要和区间[0, 60]求交集
interval solve(double a, double b)
{
// 解不等式组
interval tmp;
if (a > 0)
{
tmp.l = (D - b) / a;
tmp.r = (360 - D - b) / a;
}
else
{
tmp.l = (360 - D - b) / a;
tmp.r = (D - b) / a;
}
// 将解区间和[0, 60]求交集
if (tmp.l < 0)
tmp.l = 0;
if (tmp.r > 60)
tmp.r = 60;
// 排除其他解(例如[-3, -2]、[65, 70]这样的)
if (tmp.l >= tmp.r)
tmp.l = tmp.r = 0;
return tmp;
}
// 求两个区间的交集
interval intersection(interval a, interval b)
{
interval tmp;
tmp.l = max(a.l, b.l);
tmp.r = min(a.r, b.r);
if (tmp.l >= tmp.r)
tmp.l = tmp.r = 0;
return tmp;
}
// 计算某分钟内的happytime(单位:s)
double get_Happytime(int h, int m)
{
// deg_h = 30 * h + 0.5 * m + s /120.0
// deg_m = 6 * m + 0.1 * s
// deg_s = 6 * s
double a, b;
interval us[3][2];
// △hm = 30 * h - 6.5 * m + (1.0 / 120 - 0.1)s
a = 1.0 / 120 - 0.1;
b = 30 * h - 5.5 * m;
us[0][0] = solve(a, b);
us[0][1] = solve(-a, -b);
// △hs = 30 * h + 0.5 * m + (1.0 / 120 - 6)s
a = 1.0 / 120 - 6;
b = 30 * h + 0.5 * m;
us[1][0] = solve(a, b);
us[1][1] = solve(-a, -b);
// △ms = 6 * m + (0.1 - 6) * s
a = 0.1 - 6;
b = 6 * m;
us[2][0] = solve(a, b);
us[2][1] = solve(-a, -b);
// 对三大组不等式组的解区间、每组出一个区间求三个区间的交集,计算时间(单位:s)
interval tmp;
double res = 0;
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
for (int k = 0; k < 2; ++k)
{
tmp = intersection(intersection(us[0][i], us[1][j]), us[2][k]);
res += (tmp.r - tmp.l);
}
return res;
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
while (cin >> D, fabs(D + 1) > 1e-6)
{
double res = 0;
for (int h = 0; h < 12; ++h)
for (int m = 0; m < 60; ++m)
res += get_Happytime(h, m);
cout << fixed << setprecision(3) << res * 100 / (12 * 60 * 60) << endl;
}
return 0;
}
三、总结与吐槽
1、评价
这道题主要考验一些思维。
2、吐槽
说实话,这道题的标题设计在我看来也是有点儿坑的。
题目名字“Tick and Tick”,译为“滴答滴答”,那还不就应该是秒针一秒跳一下的那种指针吗?直接 12 × 60 × 60 12 \times 60 \times 60 12×60×60穷举完了不就好了(虽然这样的话就真成了一道水题了)。
但是题目的数据却又表明,这是一个秒针连续运动的时针……
3、后话
哎,Markdown老是设计字体、颜色什么的好心累,黑底皮肤也感觉怪怪的,还是使用最常见的皮肤和格式吧。
懒了,随缘写题解吧,网课太多快肝不动了。