/* #include "testlib.h" int main(int argc, char* argv[]){ registerValidation(argc, argv); int H = inf.readInt(1,1'000'000); inf.readSpace(); int W = inf.readInt(1, 4'000'000); ensuref((long long)H * (long long)W <= 4'000'000, "HxW violation"); inf.readEoln(); for(int i = 0; i < H; i++){ for(int j = 0; j < W; j++){ if(j > 0){ inf.readSpace(); } int A = inf.readInt(0, 1'000'000'000); } inf.readEoln(); } inf.readEof(); } */ #include #include #include #include #include #include #include #if defined(__GNUC__) #define INLINE __attribute__((always_inline)) inline #define UNLIKELY(x) __builtin_expect(!!(x), 0) #else #define INLINE inline #define UNLIKELY(x) (x) #endif namespace Validator { const char* p; const char* endp; [[noreturn]] void fail() { _exit(1); } INLINE bool digit(char c) { return static_cast(c - '0') <= 9; } // H, W 専用。 // A と違って2回しか呼ばれないので普通に数値化する。 INLINE uint32_t readInt(uint32_t lo, uint32_t hi) { if (UNLIKELY(p == endp || !digit(*p))) { fail(); } uint32_t x = 0; do { uint32_t d = *p - '0'; if (UNLIKELY(x > (hi - d) / 10)) { fail(); } x = x * 10 + d; ++p; } while (p != endp && digit(*p)); if (UNLIKELY(x < lo)) { fail(); } return x; } INLINE void readSpace() { if (UNLIKELY(p == endp || *p != ' ')) { fail(); } ++p; } INLINE void readEoln() { if (UNLIKELY(p == endp)) { fail(); } if (*p == '\n') { ++p; return; } if (*p == '\r') { if (UNLIKELY(p + 1 == endp || p[1] != '\n')) { fail(); } p += 2; return; } fail(); } // 0 <= A <= 1,000,000,000 // // 数値への変換はしない。 // 先頭の 0 を除いた桁数だけでほぼ判定できる。 INLINE void readA() { if (UNLIKELY(p == endp)) { fail(); } // testlib の readInt と同様に -0 は許容する。 if (*p == '-') { ++p; if (UNLIKELY(p == endp || !digit(*p))) { fail(); } do { if (UNLIKELY(*p != '0')) { fail(); } ++p; } while (p != endp && digit(*p)); return; } if (UNLIKELY(!digit(*p))) { fail(); } const char* s = p; // 数字列を1回走査するだけ。 do { ++p; } while (p != endp && digit(*p)); // leading zero を無視。 while (s != p && *s == '0') { ++s; } size_t n = static_cast(p - s); // 10桁より大きければ > 1e9 if (UNLIKELY(n > 10)) { fail(); } // 先頭0を除いて10桁の場合、 // <= 1e9 なのは 1000000000 のみ。 if (UNLIKELY( n == 10 && __builtin_memcmp(s, "1000000000", 10) != 0 )) { fail(); } } void validate() { int H = static_cast( readInt(1, 1'000'000) ); readSpace(); int W = static_cast( readInt(1, 4'000'000) ); if (UNLIKELY( static_cast(H) * W > 4'000'000 )) { fail(); } readEoln(); for (int i = 0; i < H; ++i) { for (int j = 0; j < W; ++j) { readA(); if (j + 1 != W) { if (UNLIKELY(p == endp || *p != ' ')) { fail(); } ++p; } } readEoln(); } if (UNLIKELY(p != endp)) { fail(); } } } // namespace Validator int main() { using namespace Validator; // stdin が通常ファイルならコピーせず mmap する。 struct stat st{}; if ( fstat(STDIN_FILENO, &st) == 0 && S_ISREG(st.st_mode) ) { size_t n = static_cast(st.st_size); if (n == 0) { return 1; } void* data = mmap( nullptr, n, PROT_READ, MAP_PRIVATE, STDIN_FILENO, 0 ); if (data != MAP_FAILED) { p = static_cast(data); endp = p + n; validate(); return 0; } } // pipe 等で mmap できない場合のみ fallback。 std::vector buf; constexpr size_t CHUNK = 1 << 20; char tmp[CHUNK]; for (;;) { ssize_t r = read( STDIN_FILENO, tmp, sizeof(tmp) ); if (r < 0) { return 1; } if (r == 0) { break; } buf.insert( buf.end(), tmp, tmp + r ); } if (buf.empty()) { return 1; } p = buf.data(); endp = p + buf.size(); validate(); }