題意:求一天當中有百分之多少時間滿足時針、分針、秒針兩兩所成角度不小於n度(所成角度不大於180度)
題解:第一次寫直接將時間離散化處理,跑完樣例才發現這樣只能求得近似解(比如當n=90時答案始終有誤差),因爲每一段滿足條件的時間段的起始時間和終止時間都不一定是1秒的整數倍。所以考慮兩兩時針在一次重合和下一次重合這個週期內有多少時間段滿足所成角度不小於n度,用三重循環(三根針兩兩組合有三種組合)枚舉這些時間段,計算被三種時間段都覆蓋一次的子段,每次答案加上這樣的子段的終止時間與起始時間之差即可。這樣的枚舉的精度遠比離散枚舉1,2,3.....秒更高。
P.S.在循環時需要剪枝(有些三元組明顯無法覆蓋同一段時間的可以直接跳過),否則答案能算對但會TLE
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const double N=12*60*60;
//speed
const double ss=6.0;
const double sm=0.1;
const double sh=0.1/12;
//relative speed
const double rsm=ss-sm;
const double rsh=ss-sh;
const double rmh=sm-sh;
//relative period of 360
const double tsm=360.0/rsm;
const double tsh=360.0/rsh;
const double tmh=360.0/rmh;
double D;
inline double Abs(double x) {
return x>0?x:-x;
}
int main() {
// freopen("in.txt","r",stdin);
while (scanf("%lf",&D)&&(D!=-1)) {
double tot=0;
//relative period of D
double dsm=D/rsm;
double dsh=D/rsh;
double dmh=D/rmh;
//relative period of 360-D
double csm=(360.0-D)/rsm;
double csh=(360.0-D)/rsh;
double cmh=(360.0-D)/rmh;
for (double i=0;i<N;i+=tsh)
for (double j=0;j<N;j+=tsm) {
if (i+csh<j+dsm) break;
if (j+csm<i+dsh) continue;
for (double k=0;k<N;k+=tmh) {
if (j+csm<k+dmh) break;
if (k+cmh<j+dsm) continue;
double a=max(max(i+dsh,j+dsm),k+dmh);
double b=min(min(i+csh,j+csm),k+cmh);
if (a<b) tot+=b-a;
}
}
printf("%.3lf\n",tot*100/N);
}
return 0;
}