#include #include using namespace std; using ll = long long int; using u64 = unsigned long long; using pll = pair; // #include // using namespace atcoder; #define REP(i, a, b) for (ll i = (a); i < (b); i++) #define REPrev(i, a, b) for (ll i = (a); i >= (b); i--) #define ALL(coll) (coll).begin(), (coll).end() #define SIZE(v) ((ll)((v).size())) #define REPOUT(i, a, b, exp, sep) REP(i, (a), (b)) cout << (exp) << (i + 1 == (b) ? "" : (sep)); cout << "\n" // @@ !! LIM(debug cmpNaive perm) // ---- inserted function f:<< from util.cc // declarations template ostream& operator<< (ostream& os, const pair& p); template ostream& operator<< (ostream& os, const tuple& t); template ostream& operator<< (ostream& os, const tuple& t); template ostream& operator<< (ostream& os, const tuple& t); template ostream& operator<< (ostream& os, const tuple& t); template ostream& operator<< (ostream& os, const vector& v); template ostream& operator<< (ostream& os, const set& v); template ostream& operator<< (ostream& os, const unordered_set& v); template ostream& operator<< (ostream& os, const multiset& v); template ostream& operator<< (ostream& os, const map& mp); template ostream& operator<< (ostream& os, const unordered_map& mp); template ostream& operator<< (ostream& os, const queue& orig); template ostream& operator<< (ostream& os, const deque& orig); template ostream& operator<< (ostream& os, const priority_queue& orig); template ostream& operator<< (ostream& os, const stack& st); #if __cplusplus >= 201703L template ostream& operator<< (ostream& os, const optional& t); #endif ostream& operator<< (ostream& os, int8_t x); ostream& operator<< (ostream& os, const __int128& x); // definitions template ostream& operator<< (ostream& os, const pair& p) { os << "(" << p.first << ", " << p.second << ")"; return os; } template ostream& operator<< (ostream& os, const tuple& t) { os << "(" << get<0>(t) << ", " << get<1>(t) << ", " << get<2>(t) << ")"; return os; } template ostream& operator<< (ostream& os, const tuple& t) { os << "(" << get<0>(t) << ", " << get<1>(t) << ", " << get<2>(t) << ", " << get<3>(t) << ")"; return os; } template ostream& operator<< (ostream& os, const tuple& t) { os << "(" << get<0>(t) << ", " << get<1>(t) << ", " << get<2>(t) << ", " << get<3>(t) << ", " << get<4>(t) << ")"; return os; } template ostream& operator<< (ostream& os, const tuple& t) { os << "(" << get<0>(t) << ", " << get<1>(t) << ", " << get<2>(t) << ", " << get<3>(t) << ", " << get<4>(t) << ", " << get<5>(t) << ")"; return os; } template ostream& operator<< (ostream& os, const vector& v) { os << '['; for (auto it = v.begin(); it != v.end(); it++) { if (it != v.begin()) os << ", "; os << *it; } os << ']'; return os; } template ostream& operator<< (ostream& os, const set& v) { os << '{'; for (auto it = v.begin(); it != v.end(); it++) { if (it != v.begin()) os << ", "; os << *it; } os << '}'; return os; } template ostream& operator<< (ostream& os, const unordered_set& v) { os << '{'; for (auto it = v.begin(); it != v.end(); it++) { if (it != v.begin()) os << ", "; os << *it; } os << '}'; return os; } template ostream& operator<< (ostream& os, const multiset& v) { os << '{'; for (auto it = v.begin(); it != v.end(); it++) { if (it != v.begin()) os << ", "; os << *it; } os << '}'; return os; } template ostream& operator<< (ostream& os, const map& mp) { os << '['; for (auto it = mp.begin(); it != mp.end(); it++) { if (it != mp.begin()) os << ", "; os << it->first << ": " << it->second; } os << ']'; return os; } template ostream& operator<< (ostream& os, const unordered_map& mp) { os << '['; for (auto it = mp.begin(); it != mp.end(); it++) { if (it != mp.begin()) os << ", "; os << it->first << ": " << it->second; } os << ']'; return os; } template ostream& operator<< (ostream& os, const queue& orig) { queue que(orig); bool first = true; os << '['; while (!que.empty()) { T x = que.front(); que.pop(); if (!first) os << ", "; os << x; first = false; } return os << ']'; } template ostream& operator<< (ostream& os, const deque& orig) { deque que(orig); bool first = true; os << '['; while (!que.empty()) { T x = que.front(); que.pop_front(); if (!first) os << ", "; os << x; first = false; } return os << ']'; } template ostream& operator<< (ostream& os, const priority_queue& orig) { priority_queue pq(orig); bool first = true; os << '['; while (!pq.empty()) { T x = pq.top(); pq.pop(); if (!first) os << ", "; os << x; first = false; } return os << ']'; } template ostream& operator<< (ostream& os, const stack& st) { stack tmp(st); os << '['; bool first = true; while (!tmp.empty()) { T& t = tmp.top(); if (first) first = false; else os << ", "; os << t; tmp.pop(); } os << ']'; return os; } #if __cplusplus >= 201703L template ostream& operator<< (ostream& os, const optional& t) { if (t.has_value()) os << "v(" << t.value() << ")"; else os << "nullopt"; return os; } #endif ostream& operator<< (ostream& os, int8_t x) { os << (int32_t)x; return os; } // for Enum type; just displays ordinals. template typename std::enable_if::value, std::ostream&>::type operator<<(std::ostream& os, E e) { return os << static_cast::type>(e); } // This is a very ad-hoc implementation... ostream& operator<<(ostream& os, const __int128& v) { unsigned __int128 a = v < 0 ? -v : v; ll i = 0; string s(64, ' '); if (v == 0) { s[i++] = '0'; }else { while (a > 0) { s[i++] = '0' + (char)(a % 10); a /= 10; } } if (v < 0) { s[i++] = '-'; } s.erase(s.begin() + i, s.end()); reverse(s.begin(), s.end()); os << s; return os; } // ---- end f:<< // ---- inserted library file debug.cc template string dbgFormat(const char* fmt, Args... args) { size_t len = snprintf(nullptr, 0, fmt, args...); char buf[len + 1]; snprintf(buf, len + 1, fmt, args...); return string(buf); } template void dbgLog(bool with_nl, Head&& head) { cerr << head; if (with_nl) cerr << endl; } template void dbgLog(bool with_nl, Head&& head, Tail&&... tail) { cerr << head << " "; dbgLog(with_nl, forward(tail)...); } #if DEBUG #define DLOG(...) dbgLog(true, __VA_ARGS__) #define DLOGNNL(...) dbgLog(false, __VA_ARGS__) #define DFMT(...) cerr << dbgFormat(__VA_ARGS__) << endl #define DCALL(func, ...) func(__VA_ARGS__) #else #define DLOG(...) #define DLOGNNL(...) #define DFMT(...) #define DCALL(func, ...) #endif /* #if DEBUG_LIB #define DLOG_LIB(...) dbgLog(true, __VA_ARGS__) #define DLOGNNL_LIB(...) dbgLog(false, __VA_ARGS__) #define DFMT_LIB(...) cerr << dbgFormat(__VA_ARGS__) << endl #define DCALL_LIB(func, ...) func(__VA_ARGS__) #else #define DLOG_LIB(...) #define DFMT_LIB(...) #define DCALL_LIB(func, ...) #endif */ #define DUP1(E1) #E1 "=", E1 #define DUP2(E1,E2) DUP1(E1), DUP1(E2) #define DUP3(E1,...) DUP1(E1), DUP2(__VA_ARGS__) #define DUP4(E1,...) DUP1(E1), DUP3(__VA_ARGS__) #define DUP5(E1,...) DUP1(E1), DUP4(__VA_ARGS__) #define DUP6(E1,...) DUP1(E1), DUP5(__VA_ARGS__) #define DUP7(E1,...) DUP1(E1), DUP6(__VA_ARGS__) #define DUP8(E1,...) DUP1(E1), DUP7(__VA_ARGS__) #define DUP9(E1,...) DUP1(E1), DUP8(__VA_ARGS__) #define DUP10(E1,...) DUP1(E1), DUP9(__VA_ARGS__) #define DUP11(E1,...) DUP1(E1), DUP10(__VA_ARGS__) #define DUP12(E1,...) DUP1(E1), DUP11(__VA_ARGS__) #define GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,NAME,...) NAME #define DUP(...) GET_MACRO(__VA_ARGS__, DUP12, DUP11, DUP10, DUP9, DUP8, DUP7, DUP6, DUP5, DUP4, DUP3, DUP2, DUP1)(__VA_ARGS__) #define DLOGK(...) DLOG(DUP(__VA_ARGS__)) #define DLOGKL(lab, ...) DLOG(lab, DUP(__VA_ARGS__)) #if DEBUG_LIB #define DLOG_LIB DLOG #define DLOGK_LIB DLOGK #define DLOGKL_LIB DLOGKL #endif // ---- end debug.cc // ---- inserted library file cmpNaive.cc const string end_mark("^__=end=__^"); int naive(istream& cin, ostream& cout); int body(istream& cin, ostream& cout); void cmpNaive() { while (true) { string s; getline(cin, s); bool run_body; if (s.at(0) == 'Q') { return; }else if (s.at(0) == 'B') { run_body = true; }else if (s.at(0) == 'N') { run_body = false; }else { cerr << "Unknown body/naive specifier.\n"; exit(1); } string input_s; while (true) { getline(cin, s); if (s == end_mark) break; input_s += s; input_s += "\n"; } stringstream ss_in(move(input_s)); stringstream ss_out; ss_out << setprecision(20); if (run_body) { body(ss_in, ss_out); }else { naive(ss_in, ss_out); } cout << ss_out.str() << end_mark << endl; } } int main(int argc, char *argv[]) { ios_base::sync_with_stdio(false); cin.tie(nullptr); cout << setprecision(20); #if CMPNAIVE if (argc == 2) { if (strcmp(argv[1], "cmpNaive") == 0) { cmpNaive(); }else if (strcmp(argv[1], "naive") == 0) { naive(cin, cout); }else if (strcmp(argv[1], "skip") == 0) { exit(0); }else { cerr << "Unknown argument.\n"; exit(1); } }else { #endif body(cin, cout); #if CMPNAIVE } #endif return 0; } /* int naive(istream& cin, ostream& cout) { return 0; } int body(istream& cin, ostream& cout) { return 0; } */ // ---- end cmpNaive.cc // ---- inserted library file perm.cc template struct IntPermBase { int n; int r; vector vec; bool started; vector mapping; bool start_check() { if constexpr (dup) { if (not ((1 <= n and 0 <= r) or (n == 0 and r == 0))) return false; } else { if (not (0 <= n and 0 <= r and r <= n)) return false; } started = true; vec.resize(r, 0); return true; } bool finish() { vec.resize(0); started = false; return false; } IntPermBase(int n_, int r_) : n(n_), r(r_), started(false) { if (n >= 0) { mapping = vector(n); for (int i = 0; i < n; i++) { if constexpr (is_integral::value) mapping[i] = (T)i; else mapping[i] = T(); } } } IntPermBase(int n_, int r_, vector mp) : n(n_), r(r_), started(false), mapping(move(mp)) { if (ssize(mapping) != n) throw runtime_error("IntPermBase: incorrect mapping length"); } T at(int i) const { return mapping[vec[i]]; } T operator[](int i) const { return at(i); } void set_mapping(auto f) { for (int i = 0; i < n; i++) mapping[i] = f(i); } vector vec_view() const { vector res; for (int i = 0; i < r; i++) res.push_back(mapping[vec[i]]); return res; } }; template struct IntPerm : IntPermBase { using Base = IntPermBase; using Base::vec, Base::r, Base::n, Base::started; vector> cands; vector cidx; bool start_check() { if (not IntPermBase::start_check()) return false; iota(vec.begin(), vec.end(), 0); cands.resize(r); cidx.resize(r); for (int i = 0; i < r; i++) { for (int j = n - 1; j >= i; j--) cands[i].push_back(j); cidx[i] = n - i - 1; } return true; } bool finish() { cands.resize(0); cidx.resize(0); return IntPermBase::finish(); } IntPerm(int n_, int r_) : IntPermBase(n_, r_) {} IntPerm(int n_, int r_, vector mp) : IntPermBase(n_, r_, mp) {} bool get() { if (not started) return start_check(); int i = r - 1; for (; i >= 0 and cidx[i] == 0; i--); if (i < 0) return finish(); vec[i] = cands[i][--cidx[i]]; for (int j = i + 1; j < r; j++) { if (j == i + 1) { cands[j].resize(0); for (int k = 0; k < (int)cands[i].size(); k++) { if (k == cidx[i]) continue; cands[j].push_back(cands[i][k]); } }else { cands[j] = cands[j - 1]; cands[j].pop_back(); } cidx[j] = n - j - 1; vec[j] = cands[j][cidx[j]]; } return true; } }; template struct IntComb : IntPermBase { using Base = IntPermBase; using Base::vec, Base::r, Base::n, Base::started, Base::finish; bool start_check() { if (not IntPermBase::start_check()) return false; iota(vec.begin(), vec.end(), 0); return true; } IntComb(int n_, int r_) : IntPermBase(n_, r_) {} IntComb(int n_, int r_, vector mp) : IntPermBase(n_, r_, mp) {} bool get() { if (not started) return start_check(); int i = r - 1; for (; i >= 0 and vec[i] == n - r + i; i--); if (i < 0) return finish(); vec[i]++; for (int j = i + 1; j < r; j++) vec[j] = vec[j - 1] + 1; return true; } }; template struct IntDupPerm : IntPermBase { using Base = IntPermBase; using Base::vec, Base::r, Base::n, Base::started, Base::finish, Base::start_check; IntDupPerm(int n_, int r_) : IntPermBase(n_, r_) {} IntDupPerm(int n_, int r_, vector mp) : IntPermBase(n_, r_, mp) {} bool get() { if (not started) return start_check(); for (int i = r - 1; i >= 0; vec[i--] = 0) if (++vec[i] < n) return true; return finish(); } }; template struct IntDupComb : IntPermBase { using Base = IntPermBase; using Base::vec, Base::r, Base::n, Base::started, Base::finish, Base::start_check; IntDupComb(int n_, int r_) : IntPermBase(n_, r_) {} IntDupComb(int n_, int r_, vector mp) : IntPermBase(n_, r_, mp) {} bool get() { if (not started) return start_check(); int i = r - 1; for (; i >= 0 and vec[i] == n - 1; i--); if (i < 0) return finish(); vec[i]++; for (int j = i + 1; j < r; j++) vec[j] = vec[i]; return true; } }; template struct IntDirProd { vector lim; int r; vector vec; bool started; IntDirProd(const vector& lim_) : lim(lim_), r(lim.size()), started(false) {} int at(int i) const { return vec[i]; } const vector& vec_view() const { return vec; } bool start_check() { for (int i = 0; i < r; i++) if (lim[i] == 0) return false; started = true; vec.resize(r, 0); return true; } bool finish() { vec.resize(0); started = false; return false; } bool get() { if (not started) return start_check(); for (int i = r - 1; i >= 0; vec[i--] = 0) if (++vec[i] < lim[i]) return true; return finish(); } }; template struct IntPartition { INT n; vector vec; bool started = false; IntPartition(INT n_) : n(n_) {} bool get() { if (not started) { started = true; vec = vector(n, 1); return true; }else if (ssize(vec) == 1) { started = false; return false; }else { ll b = vec.back(); vec.pop_back(); ll a = vec.back(); vec.pop_back(); ll c = a + b; ll a1 = a + 1; while (c - a1 >= a1) { vec.push_back(a1); c -= a1; } vec.push_back(c); return true; } } INT at(int i) const { return vec[i]; } const vector& vec_view() const { return vec; } }; // ---- end perm.cc // @@ !! LIM -- end mark -- int naive(istream& cin, ostream& cout) { ll big = 1e18; ll N, Q; cin >> N >> Q; string S; cin >> S; REP(_q, 0, Q) { ll l, r; cin >> l >> r; l--; ll len = r - l; IntPerm ip(len, len); ll ans = big; while (ip.get()) { ll t = 0; REP(i, 0, len) { t = 10 * t + '0' + S[l + ip[i]]; } if (t % 8 == 0) { ll rnum = 0; REP(i, 0, len) REP(j, i + 1, len) if (ip[i] > ip[j]) rnum++; ans = min(ans, rnum); } } if (ans == big) ans = -1; cout << ans << endl; } return 0; } int body(istream& cin, ostream& cout) { ll big = 1e18; ll N, Q; cin >> N >> Q; string S; cin >> S; vector pos(N + 1, vector(10)); pos[0] = vector(10, -1LL); REP(i, 0, N) { pos[i + 1] = pos[i]; ll d = S[i] - '0'; pos[i + 1][d] = i; } REP(i, 0, Q) { ll l, r; cin >> l >> r; l--; if (l + 1 == r) { if (S[l] == '8') { cout << 0 << "\n"; }else { cout << -1 << "\n"; } }else if (l + 2 == r) { ll x = 10 * (S[l] - '0') + 1 * (S[l + 1] - '0'); ll y = 1 * (S[l] - '0') + 10 * (S[l + 1] - '0'); ll ans = -1; if (x % 8 == 0) ans = 0; else if (y % 8 == 0) ans = 1; cout << ans << "\n"; }else { ll ans = big; REP(xx, 0, 125) { ll x = xx * 8; auto f = [&]() -> ll { ll y2 = (x / 1) % 10; ll y1 = (x / 10) % 10; ll y0 = (x / 100) % 10; ll pos2 = pos[r][y2]; if (pos2 < l) return big; ll pos1; if (y1 == y2) pos1 = pos[pos2][y1]; else pos1 = pos[r][y1]; if (pos1 < l) return big; ll pos0; if (y0 == y1) pos0 = pos[pos1][y0]; else if (y0 == y2) pos0 = pos[pos2][y0]; else pos0 = pos[r][y0]; if (pos0 < l) return big; vector w{pos0, pos1, pos2}; sort(ALL(w)); ll ret = (r - 1 - w[2]) + (r - 2 - w[1]) + (r - 3 - w[0]); DLOGK(ret); ret += (pos0 < pos1 ? 0 : 1) + (pos0 < pos2 ? 0 : 1) + (pos1 < pos2 ? 0 : 1); DLOGK(i, l, r, x, pos0, pos1, pos2, ret); return ret; }; ans = min(ans, f()); } if (ans == big) ans = -1; cout << ans << "\n"; } } return 0; }