using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Q1: " + new[]
{
new FromTo(12, 0, 13, 0),
new FromTo(10, 0, 12, 15)
}.Intersection().Normalize().Join(", "));
Console.WriteLine("Q2: " + new[]
{
new FromTo(16, 0, 23, 0),
new FromTo(9, 0, 17, 0),
new FromTo(5, 0, 10, 30)
}.Intersection().Normalize().Join(", "));
Console.WriteLine("Q3: " + new[]
{
new FromTo(12, 0, 23, 0),
new FromTo(13, 0, 14, 0),
new FromTo(15, 0, 16, 0),
new FromTo(17, 0, 18, 0),
new FromTo(19, 0, 20, 0),
new FromTo(21, 0, 22, 0)
}.Intersection().Normalize().Join(", "));
Console.WriteLine("Q4: " + new[]
{
new FromTo(10, 0, 12, 0),
new FromTo(11, 0, 11, 30),
new FromTo(10, 30, 11, 15)
}.Intersection().Normalize().Join(", "));
Console.WriteLine("Q5: " + new[]
{
new FromTo(9, 0, 17, 0),
new FromTo(19, 0, 21, 0)
}.Intersection().Normalize().Join(", "));
}
}
struct FromTo
{
public readonly TimeSpan From;
public readonly TimeSpan To;
public FromTo(TimeSpan from, TimeSpan to)
{
if (!Validate(from, to))
throw new ArgumentException();
this.From = from;
this.To = to;
}
public FromTo(int fromHours, int fromMinutes, int toHours, int toMinutes)
: this(Convert(fromHours, fromMinutes), Convert(toHours, toMinutes))
{
}
private static TimeSpan Convert(int hours, int minutes)
{
TimeSpan result = new TimeSpan(hours, minutes, 0);
if (result.Hours != hours || result.Minutes != minutes)
throw new ArgumentException();
return result;
}
private static bool Validate(TimeSpan from, TimeSpan to)
{
return (TimeSpan.Zero <= from && from <= to && to <= new TimeSpan(24, 0, 0));
}
public bool IsEmpty
{
get { return this.From == this.To; }
}
public override string ToString()
{
return string.Format(
"{0:00}:{1:00}-{2:00}:{3:00}",
this.From.Hours, this.From.Minutes, this.To.Hours, this.To.Minutes);
}
}
static class FromToEx
{
public static string Join(this IEnumerable<FromTo> source, string separator)
{
return string.Join(separator, source.Select(x => x.ToString()).ToArray());
}
public static IEnumerable<FromTo> Normalize(this IEnumerable<FromTo> source)
{
var ordered = source.OrderBy(x => x.From);
var prev = default(FromTo);
foreach (var current in ordered)
{
if (prev.To <= current.From)
{
// prevとcurrentが重なっていない
if (!prev.IsEmpty)
yield return prev;
prev = current;
}
else
{
// prevとcurrentが重なっているので、結合する
var from = prev.From;
var to = (prev.To < current.To) ? current.To : prev.To;
prev = new FromTo(from, to);
}
}
if (!prev.IsEmpty)
{
yield return prev;
}
}
public static IEnumerable<FromTo> Intersection(this IEnumerable<FromTo> source)
{
var ordered = source.OrderBy(x => x.From);
var prev = default(FromTo);
foreach (var current in ordered)
{
if (prev.To <= current.From)
{
// prevとcurrentが重なっていない
prev = current;
}
else
{
// prevとcurrentが重なっているので、重なっている部分を取り出す
var from = current.From;
var to = (prev.To < current.To) ? prev.To : current.To;
yield return new FromTo(from, to);
prev = (prev.To < current.To) ? current : prev;
}
}
}
}
dXNpbmcgU3lzdGVtOwp1c2luZyBTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYzsKdXNpbmcgU3lzdGVtLkxpbnE7CgpjbGFzcyBQcm9ncmFtCnsKICAgIHN0YXRpYyB2b2lkIE1haW4oc3RyaW5nW10gYXJncykKICAgIHsKICAgICAgICBDb25zb2xlLldyaXRlTGluZSgiUTE6ICIgKyBuZXdbXQogICAgICAgIHsKICAgICAgICAgICAgbmV3IEZyb21UbygxMiwgMCwgMTMsIDApLAogICAgICAgICAgICBuZXcgRnJvbVRvKDEwLCAwLCAxMiwgMTUpCiAgICAgICAgfS5JbnRlcnNlY3Rpb24oKS5Ob3JtYWxpemUoKS5Kb2luKCIsICIpKTsKCiAgICAgICAgQ29uc29sZS5Xcml0ZUxpbmUoIlEyOiAiICsgbmV3W10KICAgICAgICB7CiAgICAgICAgICAgIG5ldyBGcm9tVG8oMTYsIDAsIDIzLCAwKSwKICAgICAgICAgICAgbmV3IEZyb21Ubyg5LCAwLCAxNywgMCksCiAgICAgICAgICAgIG5ldyBGcm9tVG8oNSwgMCwgMTAsIDMwKQogICAgICAgIH0uSW50ZXJzZWN0aW9uKCkuTm9ybWFsaXplKCkuSm9pbigiLCAiKSk7CgogICAgICAgIENvbnNvbGUuV3JpdGVMaW5lKCJRMzogIiArIG5ld1tdCiAgICAgICAgewogICAgICAgICAgICBuZXcgRnJvbVRvKDEyLCAwLCAyMywgMCksCiAgICAgICAgICAgIG5ldyBGcm9tVG8oMTMsIDAsIDE0LCAwKSwKICAgICAgICAgICAgbmV3IEZyb21UbygxNSwgMCwgMTYsIDApLAogICAgICAgICAgICBuZXcgRnJvbVRvKDE3LCAwLCAxOCwgMCksCiAgICAgICAgICAgIG5ldyBGcm9tVG8oMTksIDAsIDIwLCAwKSwKICAgICAgICAgICAgbmV3IEZyb21UbygyMSwgMCwgMjIsIDApCiAgICAgICAgfS5JbnRlcnNlY3Rpb24oKS5Ob3JtYWxpemUoKS5Kb2luKCIsICIpKTsKCiAgICAgICAgQ29uc29sZS5Xcml0ZUxpbmUoIlE0OiAiICsgbmV3W10KICAgICAgICB7CiAgICAgICAgICAgIG5ldyBGcm9tVG8oMTAsIDAsIDEyLCAwKSwKICAgICAgICAgICAgbmV3IEZyb21UbygxMSwgMCwgMTEsIDMwKSwKICAgICAgICAgICAgbmV3IEZyb21UbygxMCwgMzAsIDExLCAxNSkKICAgICAgICB9LkludGVyc2VjdGlvbigpLk5vcm1hbGl6ZSgpLkpvaW4oIiwgIikpOwoKICAgICAgICBDb25zb2xlLldyaXRlTGluZSgiUTU6ICIgKyBuZXdbXQogICAgICAgIHsKICAgICAgICAgICAgbmV3IEZyb21Ubyg5LCAwLCAxNywgMCksCiAgICAgICAgICAgIG5ldyBGcm9tVG8oMTksIDAsIDIxLCAwKQogICAgICAgIH0uSW50ZXJzZWN0aW9uKCkuTm9ybWFsaXplKCkuSm9pbigiLCAiKSk7CiAgICB9Cn0KCnN0cnVjdCBGcm9tVG8KewogICAgcHVibGljIHJlYWRvbmx5IFRpbWVTcGFuIEZyb207CiAgICBwdWJsaWMgcmVhZG9ubHkgVGltZVNwYW4gVG87CgogICAgcHVibGljIEZyb21UbyhUaW1lU3BhbiBmcm9tLCBUaW1lU3BhbiB0bykKICAgIHsKICAgICAgICBpZiAoIVZhbGlkYXRlKGZyb20sIHRvKSkKICAgICAgICAgICAgdGhyb3cgbmV3IEFyZ3VtZW50RXhjZXB0aW9uKCk7CiAgICAgICAgdGhpcy5Gcm9tID0gZnJvbTsKICAgICAgICB0aGlzLlRvID0gdG87CiAgICB9CgogICAgcHVibGljIEZyb21UbyhpbnQgZnJvbUhvdXJzLCBpbnQgZnJvbU1pbnV0ZXMsIGludCB0b0hvdXJzLCBpbnQgdG9NaW51dGVzKQogICAgICAgIDogdGhpcyhDb252ZXJ0KGZyb21Ib3VycywgZnJvbU1pbnV0ZXMpLCBDb252ZXJ0KHRvSG91cnMsIHRvTWludXRlcykpCiAgICB7CiAgICB9CgogICAgcHJpdmF0ZSBzdGF0aWMgVGltZVNwYW4gQ29udmVydChpbnQgaG91cnMsIGludCBtaW51dGVzKQogICAgewogICAgICAgIFRpbWVTcGFuIHJlc3VsdCA9IG5ldyBUaW1lU3Bhbihob3VycywgbWludXRlcywgMCk7CiAgICAgICAgaWYgKHJlc3VsdC5Ib3VycyAhPSBob3VycyB8fCByZXN1bHQuTWludXRlcyAhPSBtaW51dGVzKQogICAgICAgICAgICB0aHJvdyBuZXcgQXJndW1lbnRFeGNlcHRpb24oKTsKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgfQoKICAgIHByaXZhdGUgc3RhdGljIGJvb2wgVmFsaWRhdGUoVGltZVNwYW4gZnJvbSwgVGltZVNwYW4gdG8pCiAgICB7CiAgICAgICAgcmV0dXJuIChUaW1lU3Bhbi5aZXJvIDw9IGZyb20gJiYgZnJvbSA8PSB0byAmJiB0byA8PSBuZXcgVGltZVNwYW4oMjQsIDAsIDApKTsKICAgIH0KCiAgICBwdWJsaWMgYm9vbCBJc0VtcHR5CiAgICB7CiAgICAgICAgZ2V0IHsgcmV0dXJuIHRoaXMuRnJvbSA9PSB0aGlzLlRvOyB9CiAgICB9CgogICAgcHVibGljIG92ZXJyaWRlIHN0cmluZyBUb1N0cmluZygpCiAgICB7CiAgICAgICAgcmV0dXJuIHN0cmluZy5Gb3JtYXQoCiAgICAgICAgICAgICJ7MDowMH06ezE6MDB9LXsyOjAwfTp7MzowMH0iLAogICAgICAgICAgICB0aGlzLkZyb20uSG91cnMsIHRoaXMuRnJvbS5NaW51dGVzLCB0aGlzLlRvLkhvdXJzLCB0aGlzLlRvLk1pbnV0ZXMpOwogICAgfQp9CgpzdGF0aWMgY2xhc3MgRnJvbVRvRXgKewogICAgcHVibGljIHN0YXRpYyBzdHJpbmcgSm9pbih0aGlzIElFbnVtZXJhYmxlPEZyb21Ubz4gc291cmNlLCBzdHJpbmcgc2VwYXJhdG9yKQogICAgewogICAgICAgIHJldHVybiBzdHJpbmcuSm9pbihzZXBhcmF0b3IsIHNvdXJjZS5TZWxlY3QoeCA9PiB4LlRvU3RyaW5nKCkpLlRvQXJyYXkoKSk7CiAgICB9CgogICAgcHVibGljIHN0YXRpYyBJRW51bWVyYWJsZTxGcm9tVG8+IE5vcm1hbGl6ZSh0aGlzIElFbnVtZXJhYmxlPEZyb21Ubz4gc291cmNlKQogICAgewogICAgICAgIHZhciBvcmRlcmVkID0gc291cmNlLk9yZGVyQnkoeCA9PiB4LkZyb20pOwogICAgICAgIHZhciBwcmV2ID0gZGVmYXVsdChGcm9tVG8pOwogICAgICAgIGZvcmVhY2ggKHZhciBjdXJyZW50IGluIG9yZGVyZWQpCiAgICAgICAgewogICAgICAgICAgICBpZiAocHJldi5UbyA8PSBjdXJyZW50LkZyb20pCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIC8vIHByZXbjgahjdXJyZW5044GM6YeN44Gq44Gj44Gm44GE44Gq44GECiAgICAgICAgICAgICAgICBpZiAoIXByZXYuSXNFbXB0eSkKICAgICAgICAgICAgICAgICAgICB5aWVsZCByZXR1cm4gcHJldjsKICAgICAgICAgICAgICAgIHByZXYgPSBjdXJyZW50OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGVsc2UKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgLy8gcHJlduOBqGN1cnJlbnTjgYzph43jgarjgaPjgabjgYTjgovjga7jgafjgIHntZDlkIjjgZnjgosKICAgICAgICAgICAgICAgIHZhciBmcm9tID0gcHJldi5Gcm9tOwogICAgICAgICAgICAgICAgdmFyIHRvID0gKHByZXYuVG8gPCBjdXJyZW50LlRvKSA/IGN1cnJlbnQuVG8gOiBwcmV2LlRvOwogICAgICAgICAgICAgICAgcHJldiA9IG5ldyBGcm9tVG8oZnJvbSwgdG8pOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIGlmICghcHJldi5Jc0VtcHR5KQogICAgICAgIHsKICAgICAgICAgICAgeWllbGQgcmV0dXJuIHByZXY7CiAgICAgICAgfQogICAgfQoKICAgIHB1YmxpYyBzdGF0aWMgSUVudW1lcmFibGU8RnJvbVRvPiBJbnRlcnNlY3Rpb24odGhpcyBJRW51bWVyYWJsZTxGcm9tVG8+IHNvdXJjZSkKICAgIHsKICAgICAgICB2YXIgb3JkZXJlZCA9IHNvdXJjZS5PcmRlckJ5KHggPT4geC5Gcm9tKTsKICAgICAgICB2YXIgcHJldiA9IGRlZmF1bHQoRnJvbVRvKTsKICAgICAgICBmb3JlYWNoICh2YXIgY3VycmVudCBpbiBvcmRlcmVkKQogICAgICAgIHsKICAgICAgICAgICAgaWYgKHByZXYuVG8gPD0gY3VycmVudC5Gcm9tKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAvLyBwcmV244GoY3VycmVudOOBjOmHjeOBquOBo+OBpuOBhOOBquOBhAogICAgICAgICAgICAgICAgcHJldiA9IGN1cnJlbnQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAvLyBwcmV244GoY3VycmVudOOBjOmHjeOBquOBo+OBpuOBhOOCi+OBruOBp+OAgemHjeOBquOBo+OBpuOBhOOCi+mDqOWIhuOCkuWPluOCiuWHuuOBmQogICAgICAgICAgICAgICAgdmFyIGZyb20gPSBjdXJyZW50LkZyb207CiAgICAgICAgICAgICAgICB2YXIgdG8gPSAocHJldi5UbyA8IGN1cnJlbnQuVG8pID8gcHJldi5UbyA6IGN1cnJlbnQuVG87CiAgICAgICAgICAgICAgICB5aWVsZCByZXR1cm4gbmV3IEZyb21Ubyhmcm9tLCB0byk7CiAgICAgICAgICAgICAgICBwcmV2ID0gKHByZXYuVG8gPCBjdXJyZW50LlRvKSA/IGN1cnJlbnQgOiBwcmV2OwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQp9