杭电-1006 Tick and Tick

2020-01-21  本文已影响0人  这样你就找不到我了

这题需要一些耐心,准备好了就来吧。

我们理解题目意思的时候注意,
A hand is happy if it is at least D degrees from any of the rest.
这句话并不是谷歌翻译的那样
“如果一只手与其余任何一只手至少有D度,那它就是快乐的”
其实题目要求是与其余所有的手(2只)都相距D度,它才是快乐的。

另外,
1,时间是连续的,三根指针之间的位置是有关系的,不能随意摆放。
2,一个圈是360度

指针之间大于D度的情况,可以描述如图

首先想到的思路是穷举所有时间,将一天24小时指针的位置全部记录下来,然后计算出结果。

另外由于24小时实际是在表盘上走了2圈,我们可以简化为求1圈的数据,即12小时指针的情况就行了。

但是按秒穷举所有时间实在太慢,我参考了前辈的思路:

零点时,三针合一,
两两指正的距离为0,
然后指针慢慢分开,
不难想象,当两两指针分开距离 全部都 超过D时,满足题目条件,
然后它们会再度重合,重新开始。(可以联系钟表想象一下其它三针合一的情况)

这样,在 重合 -> 再次重合 的过程中,有一段连续的距离是满足题目条件的。

这个距离可以这样描述 :
两两指针分离到D所用时间的最大值 (3个指针,两两看做一组)-------->

两两指针分离到D后,继续分离,到360-D距离所用时间的最小值(360-D其实就是从圆的另一端看,两指针距离小于D的情况,此时刚好不满足题目要求)

之所以是最大值是因为题目要求 全部距离D以上 ,所以必须等那三个组合中最慢的那一个完全分开D距离。

之所以是最小值同理,一旦有一个组合不满足 距离大于D 的要求,则整个系统不满足题目要求。


我们可以遍历所有指针重复的情况,并在从重复 走向 下一次重复的过程中,取符合题目要求的时间段,继而计算出结果。

具体思路见代码(已AC):

#include <iostream>
#include <algorithm>

using namespace std;
const int maxn=12*60*60;

double Max(double a,double b,double c)
{
    return max(max(a,b),c);
}
double Min(double a,double b,double c)
{
    return min(min(a,b),c);
}

int main(){
    double D;

    while(scanf("%lf",&D)&&D!=-1){
        double vh,vm,vs;//角速度,per秒
        vs = 6.0;
        vm = 1.0/10;
        vh = 1.0/120;

        double i,j,k;
        double ans=0,p,q;


        //两两指针之间运动到完全重合的时间————每过这么一段时间,该两指针就会重合
        double t_hm,t_hs,t_ms,a[7];
        t_hm = 360/(vm-vh);
        t_hs = 360/(vs-vh);
        t_ms = 360/(vs-vm);
        
        //两两指针运动 出 到相距为d的时间
        a[0] = D/(vm-vh);
        a[1] = D/(vs-vh);
        a[2] = D/(vs-vm);

        //两两指针运动 回 到相距为d的时间
        a[3] = (360-D)/(vm-vh);
        a[4] = (360-D)/(vs-vh);
        a[5] = (360-D)/(vs-vm);

        
        /*
            每一次两两指针一出一回之间,必有一段连续的距离大于D,当任意两两指针之间的距离都大于D时,满足题目要求
            再进一步分析可知,
            “两两指针运动 出 到相距为d的时间” 应取最大,因为题目要求所有的指针都happy
            “两两指针运动 回 到相距为d的时间” 应取最小,因为一旦有一对指针“回来了(相距距离小于d)”,则不满足大家都happy的题目要求
        */
    
        for(i=0;i<=1.0*maxn;i+=t_hm)
            for(j=0;j<=1.0*maxn;j+=t_hs){
                if(j+a[1]>i+a[3])break;//p>=j+a[1]&&q<=i+a[3]=>p>q=>无效
                if(i+a[0]>j+a[4])continue;
                for(k=0;k<=1.0*maxn;k+=t_ms)
                {
                    // if(k+a[2]>i+a[3]||k+a[2]>j+a[4])break;
                    // if(i+a[0]>k+a[5]||j+a[1]>k+a[5])continue;
                    p=Max(i+a[0],j+a[1],k+a[2]);//在这三个时间段刚好完成分离n度,所以取最大值才能保证全都分离n以上
                    q=Min(i+a[3],j+a[4],k+a[5]);//在这三个时间段刚好完成合并n度,所以取最小值才能保证全都未合并到n以内
                    // cout << p <<endl<< q <<endl;
                    if(q > p){
                        // cout << ans << endl;
                        ans+=q-p;
                    }
                }
            }
        printf("%.3lf\n",100.0*ans/maxn);
    }
    return 0;
}

由于本人技术比较菜,调Bug调到怀疑自我,导致此代码和其它来源代码部分雷同,见谅。

上一篇 下一篇

猜你喜欢

热点阅读