题解 P6484 【[COCI2010-2011#4] ASTRO】

SingularPoint

2020-10-17 15:54:08

Solution

### 题目大意 给出两颗星星分别在星期六第一次闪烁的时间和每两次闪烁的时间间隔,问两颗星星**是否能同时闪烁**,如果能,输出第一次同时闪烁的**星期**和**时间**。 ### 分析 明显的模拟~ ┐(—▽—)┌ 计算同时闪烁的时间很简单,先把两颗星的数据都转换成分钟单位(便于计算),然后**令所处时间靠后的星星加上下次闪烁的时间间隔**,以此类推,**直到两颗星所处时间相同**,所得到的就是第一次同时闪烁的时间。然后再把分钟数转化成 天:时:分 的形式就可以了~(要注意的是因为第一次闪烁是在星期六,所以最后的天数对 7 取模后得到的天数是从星期六开始的) 但是仅仅这样还不够,题目上还有要求:【如果两颗星星永远不会同时闪烁,则输出`Never`。】由此,我们必须想到一种方法来判断所给的数据是否能够使星星同时闪烁。 在这里,我先给出一个**结论**:(以下定义的所有时间变量单位都为 $min$) 如果我们设两颗星星开始闪烁的时间分别为:$S_1$、$S_2$,$\Delta S=|S_1-S_2|$,两颗星星每两次闪烁时间间隔分别为:$x_1$、$x_2$,那么,若两颗星星可以同时闪烁,则一定有:$\gcd(x_1,x_2)\mid\Delta S$。 接下来是证明过程: **证明** 若两颗星星能够同时闪烁,设它们第一次同时闪烁的时间为 $k$,则一定有$x_1\mid (k-S_1)$,$x_2\mid (k-S_2)$。 所以有 $\gcd(x_1,x_2)\mid (k-S_1)$,$\gcd(x_1,x_2)\mid (k-S_2)$。 可得 $\gcd(x_1,x_2)\mid [(k-S_1)-(k-S_2)]$,整理得:$\gcd(x_1,x_2)\mid\Delta S$。 证明结束。 有了上面的分析和证明,相信代码只是短短的时间问题~ ### Code ```cpp #include<bits/stdc++.h> using namespace std; int ah,am,bh,bm,xh,xm,yh,ym; int s1,s2,x1,x2; char h; int gcd(int a,int b) {return b?gcd(b,a%b):a;} int main() { scanf("%d%c%d",&ah,&h,&am); scanf("%d%c%d",&bh,&h,&bm); scanf("%d%c%d",&xh,&h,&xm); scanf("%d%c%d",&yh,&h,&ym); s1=am+ah*60;//全部转换为分钟便于计算 s2=bm+bh*60; x1=xm+xh*60; x2=ym+yh*60; int tool=s1>s2?s1-s2:s2-s1; if(tool%gcd(x1,x2)!=0){//判断能否同时闪烁 printf("Never\n"); return 0; } while(s1!=s2){ if(s1<s2) s1+=x1; if(s2<s1) s2+=x2; } int day=s1/1440; int hour,minute=s1%60; s1%=1440; hour=s1/60;//将第一次同时闪烁的时间转化为 天:时:分 的形式 day%=7; if(!day) printf("Saturday\n");//第一次闪烁是在星期六,所以取余后0代表星期六 if(day==1) printf("Sunday\n");//以此类推 if(day==2) printf("Monday\n"); if(day==3) printf("Tuesday\n"); if(day==4) printf("Wednesday\n"); if(day==5) printf("Thursday\n"); if(day==6) printf("Friday\n"); if(hour<10) printf("0"); printf("%d:",hour); if(minute<10) printf("0"); printf("%d",minute); return 0; } ``` 完结撒fa~