#pragma GCC optimize("O3,unroll-loops") #pragma GCC target("bmi,bmi2,popcnt") #include #include #include #include using namespace std; [[noreturn]] static inline void fail() { _exit(1); } static inline __attribute__((always_inline)) bool digit(unsigned char c) { return (unsigned)(c - '0') <= 9; } __attribute__((optimize("O3,unroll-loops"))) static void validate(const char* p, const char* e) { // H if (__builtin_expect(p == e || !digit(*p), 0)) fail(); unsigned H = 0; do { H = H * 10 + (*p++ - '0'); if (__builtin_expect(H > 1'000'000, 0)) fail(); } while (p != e && digit(*p)); if (__builtin_expect(H < 1, 0)) fail(); // exactly one space if (__builtin_expect(p == e || *p++ != ' ', 0)) fail(); // W if (__builtin_expect(p == e || !digit(*p), 0)) fail(); unsigned W = 0; do { W = W * 10 + (*p++ - '0'); if (__builtin_expect(W > 4'000'000, 0)) fail(); } while (p != e && digit(*p)); if (__builtin_expect( W < 1 || (uint64_t)H * W > 4'000'000, 0 )) fail(); // EOL after H W if (__builtin_expect(p == e, 0)) fail(); if (*p == '\n') { ++p; } else if ( *p == '\r' && p + 1 < e && p[1] == '\n' ) { p += 2; } else { fail(); } /* A validation. 0 <= A <= 1,000,000,000 数値変換しない。 significant digits が <= 9 -> OK ==10 -> 1000000000 のみ OK >=11 -> NG leading zero は許容。 */ const unsigned total = H * W; for (unsigned k = 0; k < total; ++k) { if (__builtin_expect(p == e || !digit(*p), 0)) fail(); /* leading zeros を読み飛ばす。 これにより 0000000000001 のような入力も高速に処理できる。 */ while (p != e && *p == '0') ++p; if (p != e && digit(*p)) { const char* s = p; /* 最大11桁だけ確認すればよい。 11 significant digits に達した時点で 必ず範囲外。 */ while ( p != e && digit(*p) && p - s < 11 ) { ++p; } size_t n = p - s; if (__builtin_expect(n >= 11, 0)) fail(); /* 10 significant digits の場合、 valid なのは 1000000000 のみ。 */ if (__builtin_expect(n == 10, 0)) { if ( s[0] != '1' || s[1] != '0' || s[2] != '0' || s[3] != '0' || s[4] != '0' || s[5] != '0' || s[6] != '0' || s[7] != '0' || s[8] != '0' || s[9] != '0' ) { fail(); } } } /* token の後ろ。 */ if (__builtin_expect(p == e, 0)) fail(); /* 行末か space かは k % W を使わない。 column counter の方が高速。 */ unsigned col = (k + 1) % W; if (col != 0) { if (__builtin_expect(*p++ != ' ', 0)) fail(); } else { if (*p == '\n') { ++p; } else if ( *p == '\r' && p + 1 < e && p[1] == '\n' ) { p += 2; } else { fail(); } } } if (__builtin_expect(p != e, 0)) fail(); } int main() { struct stat st; if ( fstat(STDIN_FILENO, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 0 ) { size_t n = (size_t)st.st_size; void* m = mmap( nullptr, n, PROT_READ, MAP_PRIVATE, STDIN_FILENO, 0 ); if (m != MAP_FAILED) { madvise(m, n, MADV_SEQUENTIAL); validate( static_cast(m), static_cast(m) + n ); return 0; } } /* pipe fallback */ constexpr size_t MAX_SIZE = 64ULL << 20; static char buf[MAX_SIZE]; size_t n = 0; while (n < MAX_SIZE) { ssize_t r = read( STDIN_FILENO, buf + n, MAX_SIZE - n ); if (r < 0) return 1; if (r == 0) break; n += r; } if (n == 0) return 1; /* 64 MiB を超えていないことも確認。 */ if (n == MAX_SIZE) { char c; if (read(STDIN_FILENO, &c, 1) != 0) fail(); } validate(buf, buf + n); }