http://projecteuler.net/index.php?section=problems&id=19
曜日の定義は1900年なのに数えるのは1901年から。何度でも騙される。
1日の曜日を出すiterableを定義する。そして、iterableの長さを得る関数を作った。数えてもいいが、zipを使えば1行で書ける。パフォーマンス的には恐らくそんなに問題ない。
template<typename T> int length(T& g) { return fst(last(zip(count<>(1), g))); }
#include <iostream> #include "itertools.h" using namespace std; using namespace itertools; int num_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; bool is_leap_year(int y) { return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0); } typedef tuple<int,int,int> triplet; // Monday is 1 class first_weekday { int y, m, w; public: first_weekday() : y(1900), m(1), w(1) { } triplet next() { auto t = triplet(y, m, w); w = next_weekday(); next_month(); return t; } bool exists_next() { return true; } int getYear() { return y; } private: int next_weekday() { if(m == 2) return (w + (is_leap_year(y) ? 29 : 28)) % 7; else return (w + num_days[m-1]) % 7; } void next_month() { if(m == 12) { y++; m = 1; } else { m++; } } }; int main() { cout << length(filter([] (triplet x) { return get<0>(x) >= 1901 && get<2>(x) == 0; }, takewhile([] (triplet x) { return get<0>(x) <= 2000; }, first_weekday()))) << endl; }