Submission #1218337


Source Code Expand

#include <bits/stdc++.h>
#include <sys/time.h>
using namespace std;
 
#define rep(i,n) for(long long i = 0; i < (long long)(n); i++)
#define repi(i,a,b) for(long long i = (long long)(a); i < (long long)(b); i++)
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define fi first
#define se second
#define mt make_tuple
#define mp make_pair
template<class T1, class T2> bool chmin(T1 &a, T2 b) { return b < a && (a = b, true); }
template<class T1, class T2> bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }
#define exists find_if
#define forall all_of
 
using ll = long long; using vll = vector<ll>; using vvll = vector<vll>; using P = pair<ll, ll>;
using ld = long double;  using vld = vector<ld>; 
using vi = vector<int>; using vvi = vector<vi>; vll conv(vi& v) { vll r(v.size()); rep(i, v.size()) r[i] = v[i]; return r; }
using Pos = complex<double>;
 
template <typename T, typename U> ostream &operator<<(ostream &o, const pair<T, U> &v) {  o << "(" << v.first << ", " << v.second << ")"; return o; }
template<size_t...> struct seq{}; template<size_t N, size_t... Is> struct gen_seq : gen_seq<N-1, N-1, Is...>{}; template<size_t... Is> struct gen_seq<0, Is...> : seq<Is...>{};
template<class Ch, class Tr, class Tuple, size_t... Is>
void print_tuple(basic_ostream<Ch,Tr>& os, Tuple const& t, seq<Is...>){ using s = int[]; (void)s{0, (void(os << (Is == 0? "" : ", ") << get<Is>(t)), 0)...}; }
template<class Ch, class Tr, class... Args> 
auto operator<<(basic_ostream<Ch, Tr>& os, tuple<Args...> const& t) -> basic_ostream<Ch, Tr>& { os << "("; print_tuple(os, t, gen_seq<sizeof...(Args)>()); return os << ")"; }
ostream &operator<<(ostream &o, const vvll &v) { rep(i, v.size()) { rep(j, v[i].size()) o << v[i][j] << " "; o << endl; } return o; }
template <typename T> ostream &operator<<(ostream &o, const vector<T> &v) { o << '['; rep(i, v.size()) o << v[i] << (i != v.size()-1 ? ", " : ""); o << "]";  return o; }
template <typename T>  ostream &operator<<(ostream &o, const set<T> &m) { o << '['; for (auto it = m.begin(); it != m.end(); it++) o << *it << (next(it) != m.end() ? ", " : ""); o << "]";  return o; }
template <typename T, typename U>  ostream &operator<<(ostream &o, const map<T, U> &m) { o << '['; for (auto it = m.begin(); it != m.end(); it++) o << *it << (next(it) != m.end() ? ", " : ""); o << "]";  return o; }
template <typename T, typename U, typename V>  ostream &operator<<(ostream &o, const unordered_map<T, U, V> &m) { o << '['; for (auto it = m.begin(); it != m.end(); it++) o << *it; o << "]";  return o; }
vector<int> range(const int x, const int y) { vector<int> v(y - x + 1); iota(v.begin(), v.end(), x); return v; }
template <typename T> istream& operator>>(istream& i, vector<T>& o) { rep(j, o.size()) i >> o[j]; return i;}
string bits_to_string(ll input, ll n=64) { string s; rep(i, n) s += '0' + !!(input & (1ll << i)); reverse(all(s)); return s; }
 
template <typename T> unordered_map<T, ll> counter(vector<T> vec){unordered_map<T, ll> ret; for (auto&& x : vec) ret[x]++; return ret;};
string substr(string s, P x) {return s.substr(x.fi, x.se - x.fi); }
struct ci : public iterator<forward_iterator_tag, ll> { ll n; ci(const ll n) : n(n) { } bool operator==(const ci& x) { return n == x.n; } bool operator!=(const ci& x) { return !(*this == x); } ci &operator++() { n++; return *this; } ll operator*() const { return n; } };
 
size_t random_seed; namespace std { using argument_type = P; template<> struct hash<argument_type> { size_t operator()(argument_type const& x) const { size_t seed = random_seed; seed ^= hash<ll>{}(x.fi); seed ^= (hash<ll>{}(x.se) << 1); return seed; } }; }; // hash for various class
namespace myhash{ const int Bsizes[]={3,9,13,17,21,25,29,33,37,41,45,49,53,57,61,65,69,73,77,81}; const int xor_nums[]={0x100007d1,0x5ff049c9,0x14560859,0x07087fef,0x3e277d49,0x4dba1f17,0x709c5988,0x05904258,0x1aa71872,0x238819b3,0x7b002bb7,0x1cf91302,0x0012290a,0x1083576b,0x76473e49,0x3d86295b,0x20536814,0x08634f4d,0x115405e8,0x0e6359f2}; const int hash_key=xor_nums[rand()%20]; const int mod_key=xor_nums[rand()%20]; template <typename T> struct myhash{ std::size_t operator()(const T& val) const { return (hash<T>{}(val)%mod_key)^hash_key; } }; };
template <typename T> class uset:public std::unordered_set<T,myhash::myhash<T>> { using SET=std::unordered_set<T,myhash::myhash<T>>; public: uset():SET(){SET::rehash(myhash::Bsizes[rand()%20]);} };
template <typename T,typename U> class umap:public std::unordered_map<T,U,myhash::myhash<T>> { public: using MAP=std::unordered_map<T,U,myhash::myhash<T>>; umap():MAP(){MAP::rehash(myhash::Bsizes[rand()%20]);} };    
 
struct timeval start; double sec() { struct timeval tv; gettimeofday(&tv, NULL); return (tv.tv_sec - start.tv_sec) + (tv.tv_usec - start.tv_usec) * 1e-6; }
struct init_{init_(){ gettimeofday(&start, NULL); ios::sync_with_stdio(false); cin.tie(0); srand((unsigned int)time(NULL)); random_seed = RAND_MAX / 2 + rand() / 2; }} init__;
 
static const double EPS = 1e-14;
static const long long INF = 1e18;
static const long long mo = 1e9+7;
#define ldout fixed << setprecision(40) 
const int DEBUG = 0;
ll h, w; 
double g_gamma = 0.90;

// 標準入力からの質問応答
ll ask_from_stdin(ll x1, ll y1, ll x2, ll y2) {
    cout << "? " << x1 << " " << y1 << " " << x2 << " " << y2 << endl;
    ll ret; cin >> ret; return ret;
}

// 答えからの質問応答
vvll b_ans(50, vll(50, -1));
void set_answer(vvll& input) {
    b_ans = input;
}
ll ask_from_answer(ll x1, ll y1, ll x2, ll y2) {
    ll ret = 0;
    repi(i, x1, x2+1) repi(j, y1, y2+1) if (b_ans[i][j]) ret++;
    return ret;
}
ll ask_num = 0;
ll ask(ll x1, ll y1, ll x2, ll y2) {
    ask_num++;
    if (DEBUG) 
        return ask_from_answer(x1, y1, x2, y2);
    else 
        return ask_from_stdin(x1, y1, x2, y2);
}

vvll b;
// [(x1, y1), (x2, y2)]にn個爆弾がある場合に確定する。
void rec(ll x1, ll y1, ll x2, ll y2, ll n) {
    assert(x1 <= x2);
    assert(y1 <= y2);
    assert(x1 >= 0 && y1 >= 0);
    assert(x2 <= 49 && y2 <= 49);
    if (n == 0 || n == (x2-x1+1)*(y2-y1+1)) {
        repi(i, x1, x2+1) repi(j, y1, y2+1)
            b[i][j] = !!n;
        return;
    }
 
    if (x1 == x2) {
        ll m = y1+(y2-y1)/2;
        ll l = ask(x1, y1, x2, m);
        rec(x1, y1, x2, m, l);
        ll u = n - l;
        rec(x1, m+1, x2, y2, u);
    } else {
        ll m = x1+(x2-x1)/2;
        ll l = ask(x1, y1, m, y2);
        rec(x1, y1, m, y2, l);
        ll u = n - l;
        rec(m+1, y1, x2, y2, u);
    }
}
pair<vvll, ll> rec_main(ll h, ll w, ll n, ll h0 = 0, ll w0 = 0) {
    if (DEBUG) 
        n = ask(0, 0, h-1, w-1);

    ask_num = 0;

    b = vvll(h+h0, vll(w+w0, -1));
    rec(h0, w0, h0+h-1, w0+w-1, n);
    vvll b_ret(h, vll(w));
    rep(i, h) rep(j, w)
        b_ret[i][j] = b[h0+i][w0+j];
    return mp(b_ret, ask_num);
}

ll compress(vvll& b, ll h, ll w, ll k) {
    ll ret = 0;
    vll two(10000); two[0] = 1; rep(i, two.size()-1) two[i+1] = (two[i] * 2ll) % k;
    rep(i, h) rep(j, w) if (b[i][j]) (ret += two[i*w+j]) %= k;
    return ret;
}

void print_board(vvll& b, ll h, ll w) {
    rep(i, h) rep(j, w) assert(b[i][j] != -1);
    rep(i, h) { 
        rep(j, w) cout << b[i][j] << " ";
        cout << endl;
    }
}

// state = 最大h*w個のペア(ll 質問mask, ll 返答);
// 2x2なら状態9^4=6561くらい、nがはじめに与えられるから少しは減る…?
// 3x2なら状態16^6=1700万くらい <-すでにやばそう
// 4x2なら状態24^8くらい
// 3x3なら状態54^9くらい
// 2x2なら行けそうだけど、3x3でもう結構状態量がやばい
using state = vector<P>;
map<state, ll> memo_countSolution;
ll countSolution(state s) {
    if (memo_countSolution.count(s)) return memo_countSolution[s];
    ll ret = 0;
    rep(mask, (1ll << (h*w))) {
        // maskがすべてのstateに合致しているか
        rep(i, s.size()) 
            if (__builtin_popcount(mask & s[i].fi) != s[i].se) 
                goto SKIP;
        ret++;
//        if (ret > 1) break; // 0, 1, 2しか興味がない
        SKIP:;
    }
    return memo_countSolution[s] = ret;
}
vll enumerateSolution(state s) {
    vll ret;
    rep(mask, (1ll << (h*w))) {
        // maskがすべてのstateに合致しているか
        rep(i, s.size()) 
            if (__builtin_popcount(mask & s[i].fi) != s[i].se) 
                goto SKIP;

        ret.pb(mask);
//        if (ret > 1) break; // 0, 1, 2しか興味がない
        SKIP:;
    }
    return ret;
}

vll histogramSolution(state s, ll next_query_board) {
    vll ret(h*w+1);
    rep(mask, (1ll << (h*w))) {
        rep(i, s.size()) 
            if (__builtin_popcount(mask & s[i].fi) != s[i].se) 
                goto SKIP;
        // maskがすべてのstateに合致している
        ret[__builtin_popcount(mask & next_query_board)]++;
        SKIP:;
    }
    return ret;
}

void test_countSolotion(void) {
    assert(h == 2), assert(w == 2);
    {
        assert(countSolution({P(0b1111, 0)}) == 1);
        assert(countSolution({P(0b1111, 1)}) == 4);
        assert(countSolution({P(0b1111, 2)}) == 6);
        assert(countSolution({P(0b1111, 3)}) == 4);
        assert(countSolution({P(0b1111, 4)}) == 1);

        assert(countSolution({P(0b1111, 2), P(0b1010, 1)}) == 4);
    }
}

struct edge_t {
    state s;
    double p;
    ll r;
};
ostream &operator<<(ostream &o, const edge_t &e) {  
    o << "(" << e.s << ", " << e.p << ", " << e.r << ") "; return o; 
}


map<state, ll> all_states;
map<ll, state> all_states_rev;
map<ll, map<ll, vector<tuple<ll, double, double>>>> pr; // pr[s][a] = [(s'2, p2, r2), (s'1, p1, r1) ...  ]
void addState(state s) {
    if (!all_states.count(s)) {
        ll all_states_size = all_states.size();
        all_states[s] = all_states_size;
        all_states_rev[all_states_size] = s;
    }
}

map<tuple<ll, ll, ll, ll>, ll> all_actions; // h1, h2, w1, w2
map<ll, tuple<ll, ll, ll, ll>> all_actions_rev;
void addAction(ll h1, ll h2, ll w1, ll w2) {
    auto action = tie(h1, h2, w1, w2);
    if (!all_actions.count(action)) {
        ll all_actions_size = all_actions.size();
        all_actions[action] = all_actions_size;
        all_actions_rev[all_actions_size] = action;
    }
}
ll getQueryFromHW(ll h1, ll h2, ll w1, ll w2) {
    ll mask = 0;
    repi(hh, h1, h2+1) repi(ww, w1, w2+1) mask |= (1ll << (hh*w+ww));
    return mask;
}
void transite(state s, vector<edge_t>& ret) {
    addState(s);
    if (countSolution(s) == 1) return;
    if (s.size() > h * w - 1) return; // 長さh*wで絶対終わるので
    ret.clear();

    rep(h1, h) rep(w1, w) repi(h2, h1, h) repi(w2, w1, w) {
        addAction(h1, h2, w1, w2);
    }
    rep(h1, h) rep(w1, w) repi(h2, h1, h) repi(w2, w1, w) {
        ll next_query_board = getQueryFromHW(h1, h2, w1, w2);

        vll histogram_of_solution_s_next = histogramSolution(s, next_query_board);
        ll histogram_of_solution_sum = accumulate(all(histogram_of_solution_s_next), 0ll);

        rep(ret_ask, h*w+1) {
            // 状態sから、行動a=(h1, w1, h2, w2)を行った結果、
            // ret_askを受け取って状態s_nextに変動する確率と、その時に得られる報酬
            //
            state s_next = s;
            P next_query = P(next_query_board, ret_ask);

            // すでに聞いたことがある
            ll flag = 0; for (auto q : s) if (q == next_query) flag = 1;
            if (flag) continue;

            s_next.pb(next_query);
            sort(all(s_next));
            ll num_of_solution_s_next = countSolution(s_next);

            if (!num_of_solution_s_next) continue; // 解が存在しないような状態には遷移しない
            if (s_next.size() >= h*w && num_of_solution_s_next != 1) continue; // h*w回クエリもらってるのに解が1位に定まらないような状態には遷移しない
            edge_t tmp;
            tmp.s = s_next;
#if 0
            tmp.r = num_of_solution_s - num_of_solution_s_next;
#else
            if (num_of_solution_s_next == 1) 
                tmp.r = 1;
            else 
                tmp.r = -1;
#endif
//            tmp.r = 0; // デバッグ用。これがonなのに性能が高かったらおかしい。
            tmp.p = (double)histogram_of_solution_s_next[ret_ask] / histogram_of_solution_sum; 
            ret.pb(tmp);

            addState(s_next);
            pr[all_states[s]][all_actions[tie(h1, h2, w1, w2)]].pb(tie(all_states[s_next], tmp.p, tmp.r));
        }
    }
}


ll transitFromID(ll si, ll ai) {
    state s = all_states_rev[si];

    ll h1, h2, w1, w2; tie(h1, h2, w1, w2) = all_actions_rev[ai];
    ll ret_of_ask = ask_from_answer(h1, w1, h2, w2);

    ll mask = getQueryFromHW(h1, h2, w1, w2);

    s.pb(P(mask, ret_of_ask));
    sort(all(s));
    assert(all_states.count(s));
    return all_states[s];
}

void test(void) {
    test_countSolotion();
}

ll evaluateBinarySearch(ll mask) {
    rep(hh, h) rep(ww, w) 
        b_ans[hh][ww] = !!(mask & (1ll << (hh*w+ww)));
    rec_main(h, w, -1/*bomb num*/);
    return ask_num;
}
double expectValOfEvaluateBinarySearch(ll n) {
    double ret = 0;
    ll num = 0;
    rep(mask, 1ll << (h*w)) if (__builtin_popcount(mask) == n) {
        num++;
        ret += evaluateBinarySearch(mask);
    }
    return ret / num;
}

ll evaluatePolicy(ll mask, state initial_state, vll& pi) {
    rep(hh, h) rep(ww, w) 
        b_ans[hh][ww] = !!(mask & (1ll << (hh*w+ww)));

    assert(all_states.count(initial_state));
    ll si = all_states[initial_state];
    ll ret = 0;
    while (1) {
        ll a = pi[si];
        if (a == -1) return ret;

        ll h1, h2, w1, w2; tie(h1, h2, w1, w2) = all_actions_rev[a];
        state s = all_states_rev[si];
        state next_s = all_states_rev[si];
        next_s.pb(P(getQueryFromHW(h1, h2, w1, w2), ask(h1, w1, h2, w2)));
        sort(all(next_s));
        assert(all_states.count(next_s));
        si = all_states[next_s];
        ret++;
    }

    assert(0);
    return -1;
}
double expectValOfEvaluatePolicy(ll n, state initial_state, vll& pi) {
    double ret = 0;
    ll num = 0;
    rep(mask, 1ll << (h*w)) if (__builtin_popcount(mask) == n) {
        num++;
        ret += evaluatePolicy(mask, initial_state, pi);
    }
    return ret / num;
}

vector<double> calculateV(void) {
    ll sn = all_states.size();
    ll an = all_actions.size();
    vector<double> V(sn, 0); // v(s) : 状態価値
    double delta = INF;
    while (delta > 1e-10) {
        delta = 0;
        rep(s, sn) {
            // 終端条件
            if (!pr[s].size()) {
                V[s] = 0;
                continue; 
            }
            double prev_v = V[s];
            double v_max = -INF;
            double v_max_a = -INF;
            rep(a, an) if (pr[s].count(a)) {
                double sum = 0;
                for (auto&& spr_dash : pr[s][a]) {
                    int s_dash; double p, r; tie(s_dash, p, r) = spr_dash;
                    sum += p * (r + g_gamma * V[s_dash]);
                }
                if (v_max < sum) {
                    v_max = sum;
                    v_max_a = a;
                }
            }
            V[s] = v_max;
            delta += abs(V[s] - prev_v);
        }
    }
    // assert
    // 初期値をちょっと変えて、同じ場所に収束する

    return V;
}

vll calculatePi(vector<double>& V) {
    ll sn = all_states.size();
    ll an = all_actions.size();
    vector<ll> pi(sn); // pi(s) : S -> A
    {
        rep(s, sn) {
            // 終端条件
            if (!pr[s].size()) {
                pi[s] = -1;
                continue; 
            }
            double v_max = -INF;
            double v_max_a = -INF;
            rep(a, an) if (pr[s].count(a)) {
                double sum = 0;
                for (auto&& spr_dash : pr[s][a]) {
                    int s_dash; double p, r; tie(s_dash, p, r) = spr_dash;
                    sum += p * (r + g_gamma * V[s_dash]);
                }
                if (v_max < sum) {
                    v_max = sum;
                    v_max_a = a;
                }
            }
            pi[s] = v_max_a;
            assert(pi[s] == -INF || pr[s].count(pi[s]));
        }
    }
    rep(s, sn) if (pr[s].size() != 0) assert(pi[s] != -INF);

    return pi;
}

pair<vvll, ll> determineBoardFromPolicy(ll h, ll w, ll num, vll pi, ll offset_h = 0, ll offset_w = 0) {
    state s = {P((1ll<<(h*w))-1,num)};
    ll ret_num = 0;
    while (1) {
        // TODO countSolutionに変更
        ll cs = 0;
        rep(mask, (1ll << (h*w))) {
            rep(i, s.size()) 
                if (__builtin_popcount(mask & s[i].fi) != s[i].se) 
                    goto SKIP;
            cs++;
            SKIP:;
        }
        if (cs == 1) break;

        ret_num++;

        ll si = all_states[s];
        ll ai = pi[si];
        ll h1, h2, w1, w2; tie(h1, h2, w1, w2) = all_actions_rev[ai];

        ll n = ask(offset_h+h1, offset_w+w1, offset_h+h2, offset_w+w2);

        ll mask = 0;
        repi(hh, h1, h2+1) repi(ww, w1, w2+1) 
            mask |= (1ll << (hh*w+ww));

        s.pb(P(mask, n));
        sort(all(s));
        assert(all_states.count(s));
    }
    vll ret = enumerateSolution(s);
    assert(ret.size() == 1);
    ll b_mask = ret[0];

    vvll ret_b(h, vll(w, 0));
    rep(hh, h) rep(ww, w) if (b_mask & (1ll << (hh*w+ww))){
        ret_b[hh][ww] = 1;
    }
    return mp(ret_b, ret_num);
}
int main(void) {
    h = 2, w = 2;

    //    test();

    queue<state> q;

    state initial_state = {P((1ll<<(h*w))-1, 2)};
    q.push(initial_state);
    addState(initial_state);

    set<state> used;
    used.insert(initial_state);
    while(!q.empty()) {
        state s = q.front(); q.pop();

        vector<edge_t> edges;
        transite(s, edges);
        for (auto&& e : edges) {
            if (used.count(e.s)) continue;
            used.insert(e.s);
            q.push(e.s);
        }
    }
//    cout << "# state num = " << all_states.size() << endl;
//    cout << "# action num = " << all_actions.size() << endl;

    for(auto x : all_states) {
        state s = x.fi;
        ll si = x.se;
        if (countSolution(s) == 1) 
            assert(pr[si].size() == 0);
    }

    //    cout << "# state size = " << all_states.size() << endl;
    //    cout << "# All States " << endl;
    //    for (auto x : all_states)  cout << x.se << " " << x.fi << " " << countSolution(x.fi)<< endl; 
    //    cout << "# All Actions " << endl;
    //    for (auto x : all_actions) cout << x.se << " " << x.fi << endl;
    //    cout << "# Prob, Reward " << endl;
    //    for (auto pr_s : pr) { ll s = pr_s.fi; for (auto pr_sa : pr_s.se) { ll a = pr_sa.fi; cout << s << " " << a << " " << pr_sa.se << endl; } }


    vector<double> V = calculateV();
    vll pi = calculatePi(V);

    ll g_h, g_w, n; cin >> g_h >> g_w >> n; 
       ll k; cin >> k;
    vvll ret(g_h, vll(g_w));
    ll all_ret_num = 0;
    ll hs = 2, ws = 2; // h size, w size
    rep(i, g_h/hs) rep(j, g_w/ws) {
        ll num = ask(i*hs, j*ws, i*hs+1, j*ws+1); // h1, w1, h2, w2

        vvll ret_b; ll ret_num;
        if (num == 2) 
            tie(ret_b, ret_num) = determineBoardFromPolicy(hs, ws, num, pi, i*hs, j*ws);
        else 
            tie(ret_b, ret_num) = rec_main(2, 2, num, i*hs, j*ws);

        all_ret_num += ret_num + 1;
        rep(hh, hs) rep(ww, ws)
            ret[i*hs+hh][j*ws+ww] = ret_b[hh][ww];
    }
    /*
    rep(i, g_h) { 
        rep(j, g_w) {
            cout << ret[i][j] << " ";
        }
        cout << endl;
    }
    */

    /*
    cout << expectValOfEvaluateBinarySearch(2) << endl;
    cout << expectValOfEvaluatePolicy(2, initial_state, pi) << endl;
    */
       cout << "! " << compress(ret, g_h, g_w, k) << endl;
    return 0;
}

Submission Info

Submission Time
Task H - Bombs Searching Game
User hamko
Language C++14 (GCC 5.4.1)
Score 453
Code Size 20381 Byte
Status AC
Exec Time 51 ms
Memory 1492 KB

Judge Result

Set Name Text1 Text2 Text3 Text4 Text5
Score / Max Score 88 / 300 91 / 300 93 / 300 91 / 300 90 / 300
Status
AC × 1
AC × 1
AC × 1
AC × 1
AC × 1
Set Name Test Cases
Text1 in1.txt
Text2 in2.txt
Text3 in3.txt
Text4 in4.txt
Text5 in5.txt
Case Name Status Exec Time Memory
in1.txt AC 47 ms 1484 KB
in2.txt AC 49 ms 1488 KB
in3.txt AC 50 ms 1488 KB
in4.txt AC 48 ms 1492 KB
in5.txt AC 51 ms 1488 KB