Problem:
Problem Statement
Have you experienced $10$-by-$10$ grid calculation? It's a mathematical exercise common in Japan. In this problem, we consider the generalization of the exercise, $N$-by-$M$ grid calculation.
In this exercise, you are given an $N$-by-$M$ grid (i.e. a grid with $N$ rows and $M$ columns) with an additional column and row at the top and the left of the grid, respectively. Each cell of the additional column and row has a positive integer. Let's denote the sequence of integers on the column and row by $a$ and $b$, and the $i$-th integer from the top in the column is $a_i$ and the $j$-th integer from the left in the row is $b_j$, respectively.
Initially, each cell in the grid (other than the additional column and row) is blank. Let $(i, j)$ be the cell at the $i$-th from the top and the $j$-th from the left. The exercise expects you to fill all the cells so that the cell $(i, j)$ has $a_i \times b_j$. You have to start at the top-left cell. You repeat to calculate the multiplication $a_i \times b_j$ for a current cell $(i, j)$, and then move from left to right until you reach the rightmost cell, then move to the leftmost cell of the next row below.
At the end of the exercise, you will write a lot, really a lot of digits on the cells. Your teacher, who gave this exercise to you, looks like bothering to check entire cells on the grid to confirm that you have done this exercise. So the teacher thinks it is OK if you can answer the $d$-th
digit
(not
integer
, see an example below), you have written for randomly chosen $x$. Let's see an example.
For this example, you calculate values on cells, which are $8$, $56$, $24$, $1$, $7$, $3$ in order. Thus, you would write digits 8, 5, 6, 2, 4, 1, 7, 3. So the answer to a question $4$ is $2$.
You noticed that you can answer such questions even if you haven't completed the given exercise. Given a column $a$, a row $b$, and $Q$ integers $d_1, d_2, \dots, d_Q$, your task is to answer the $d_k$-th digit you would write if you had completed this exercise on the given grid for each $k$. Note that your teacher is not so kind (unfortunately), so may ask you numbers greater than you would write. For such questions, you should answer 'x' instead of a digit.
Input
The input consists of a single test case formatted as follows.
$N$ $M$
$a_1$ $\ldots$ $a_N$
$b_1$ $\ldots$ $b_M$
$Q$
$d_1$ $\ldots$ $d_Q$
The first line contains two integers $N$ ($1 \le N \le 10^5$) and $M$ ($1 \le M \le 10^5$), which are the number of rows and columns of the grid, respectively.
The second line represents a sequence $a$ of $N$ integers, the $i$-th of which is the integer at the $i$-th from the top of the additional column on the left. It holds $1 \le a_i \le 10^9$ for $1 \le i \le N$.
The third line represents a sequence $b$ of $M$ integers, the $j$-th of which is the integer at the $j$-th from the left of the additional row on the top. It holds $1 \le b_j \le 10^9$ for $1 \le j \le M$.
The fourth line contains an integer $Q$ ($1 
...(truncated)

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ll = long long;
using ld = long double;

template <typename T>
class fenwick_tree {
public:
    fenwick_tree(int n_) : n(n_), dat(n_) {}

    void add(int i, T val) {
        for(; i < n; i |= i + 1) {
            dat[i] += val;
        }
    }

    ll sum(int i) const {
        T res = 0;
        for(; i >= 0; i = (i & (i + 1)) - 1) {
            res += dat[i];
        }
        return res;
    }
    T sum(int l, int r) const {
        return sum(r - 1) - sum(l - 1);
    }

private:
    const int n;
    vector<T> dat;
};

pair<ld, ll> decomp(ld val) {
    int cnt = 0;
    while(val >= 10.0) {
        cnt += 1;
        val /= 10;
    }
    return make_pair(val, cnt);
}

int main() {
    ios_base::sync_with_stdio(false); cin.tie(0);

    int n, m; cin >> n >> m;
    vector<ll> a(n), b(m);
    for(auto& x : a) cin >> x;
    for(auto& x : b) cin >> x;

    fenwick_tree<ll> sum_b(m + 1);
    vector<pair<ld, int>> bs(m);
    for(int i = 0; i < m; ++i) {
        auto p = decomp(b[i]);
        sum_b.add(i, p.second + 1);
        bs[i] = make_pair(p.first, i);
    }
    sort(bs.begin(), bs.end());

    vector<ll> sum(n + 1);
    vector<pair<ld, ll>> aval(n);
    for(int i = 0; i < n; ++i) {
        auto p = decomp(a[i]);
        aval[i] = p;
        sum[i + 1] = sum[i] + p.second * m + sum_b.sum(0, m);
        sum[i + 1] += bs.end() - lower_bound(bs.begin(), bs.end(), make_pair(10.0L / p.first, -1));
    }
    reverse(bs.begin(), bs.end());

    int q; cin >> q;
    vector<ll> d(q), aidx(q);
    string ans(q, ' ');
    for(int i = 0; i < q; ++i) {
        cin >> d[i];
        int lb = 0, ub = n + 1;
        while(ub - lb > 1) {
            const int mid = (ub + lb) / 2;
            (sum[mid] >= d[i] ? ub : lb) = mid;
        }
        if(ub == n + 1) {
            ans[i] = 'x';
        } else {
            aidx[i] = lb;
        }
    }
    vector<int> qord(q);
    iota(qord.begin(), qord.end(), 0);
    sort(qord.begin(), qord.end(), [&] (int i, int j) { return aval[aidx[i]].first < aval[aidx[j]].first; });

    int b_it = 0;
    for(auto const qi : qord) {
        if(ans[qi] == 'x') continue;
        const int ai = aidx[qi];
        while(b_it < m && bs[b_it].first * aval[ai].first >= 10.0L) {
            sum_b.add(bs[b_it++].second, 1);
        }
        ll lb = 0, ub = m;
        while(ub - lb > 1) {
            const int mid = (lb + ub) / 2;
            const ll s = sum[ai] + sum_b.sum(0, mid) + aval[ai].second * mid;
            (s >= d[qi] ? ub : lb) = mid;
        }
        const ll offset = d[qi] - (sum[ai] + sum_b.sum(0, lb) + aval[ai].second * lb);
        ans[qi] = to_string(a[ai] * b[lb])[offset - 1];
    }

    cout << ans << endl;
}
accuracy: 1
time_ms: 210
memory_kb: 18844
final_rank: 2

code_snippet: #ifdef NACHIA
#define _GLIBCXX_DEBUG
#endif

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
template<class T> using V = vector<T>;
const ll INF = 1ll << 60;
#define rep(i,n) for(int i=0; i<int(n); i++)
template<class A, class B> void chmax(A& l, const B& r){ if(l < r) l = r; }
template<class A, class B> void chmin(A& l, const B& r){ if(r < l) l = r; }


struct Fenwick {
  vector<int> A;
  int msb;
  Fenwick(int n = 0){
    A.assign(n+1, 0);
    msb = 1;
    while(msb * 2 <= n) msb *= 2;
  }
  void add(int p, int v){
    p += 1;
    while(p < int(A.size())){
      A[p] += v;
      p += p & -p;
    }
  }
  int ubound(ll& s){
    int r = 0;
    for(int t=msb; t; t/=2){
      if(r + t >= int(A.size())) continue;
      if(s >= A[r+t]){
        s -= A[r+t];
        r += t;
      }
    }
    return r;
  }
};

void testcase(){
  int N, M; cin >> N >> M;
  vector<ll> A(N), B(M);
  rep(i,N) cin >> A[i];
  rep(i,M) cin >> B[i];

  vector<int> I(M); rep(i,M) I[i] = i;
  sort(I.begin(), I.end(), [&](int l, int r){ return B[l] < B[r]; });
  V<int> J(N); rep(i,N) J[i] = i;
  sort(J.begin(), J.end(), [&](int l, int r){ return A[l] < A[r]; });

  vector<ll> AI(N); rep(i,N) AI[i] = A[J[i]];
  vector<int> initBdig(M); rep(i,M) initBdig[i] = to_string(B[i]).size();

  vector<ll> p10(19);
  p10[0] = 1;
  rep(i,18) p10[i+1] = p10[i] * 10;

  V<V<int>> que(N);
  rep(i,M){
    ll b = B[i];
    for(ll t=initBdig[i]; t<=18; t++){
      ll c = (p10[t] - 1) / b + 1;
      ll a = lower_bound(AI.begin(), AI.end(), c) - AI.begin();
      if(a != N) que[a].push_back(i);
    }
  }

  vector<ll> pref(N+1); {
    vector<ll> sa(N+1);
    for(int d : initBdig) sa[0] += d;
    rep(i,N) sa[i+1] = sa[i] + que[i].size();
    rep(i,N) pref[J[i]+1] = sa[i+1];
    rep(i,N) pref[i+1] += pref[i];
  }

  //cout << "pref : "; for(auto a : pref){ cout << a << " "; } cout << endl;

  int Q; cin >> Q;
  vector<ll> D(Q); rep(i,Q){ cin >> D[i]; D[i]--; }
  V<V<pair<int,ll>>> D2(N);
  vector<char> ans(Q, '-');
  rep(qi,Q){
    ll q = D[qi];
    ll p = upper_bound(pref.begin(), pref.end(), q) - pref.begin();
    if(p == N+1){ ans[qi] = 'x'; continue; }
    //cout << "qi = " << qi << " , p = " << (p-1) << " , q = " << (q - pref[p-1]) << endl;
    D2[p-1].push_back({ qi, q - pref[p-1] });
  }

  Fenwick ds(M);
  rep(i,M) ds.add(i, initBdig[i]);
  rep(i,N){
    for(auto p : que[i]) ds.add(p, 1);
    for(auto [qi,u] : D2[J[i]]){
      int r = ds.ubound(u);
      //cout << "u = " << u << " , r = " << r << endl;
      ans[qi] = to_string(AI[i] * B[r])[u];
    }
  }
  
  for(auto c : ans) cout << char(c);
  cout << "\n";
}


int main(){
  cin.tie(0)->sync_with_stdio(0);
  testcase();
  return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 27924
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ll = long long;
using ld = long double;

template <typename T>
class fenwick_tree {
public:
    fenwick_tree(int n_) : n(n_), dat(n_) {}

    void add(int i, T val) {
        for(; i < n; i |= i + 1) {
            dat[i] += val;
        }
    }

    ll sum(int i) const {
        T res = 0;
        for(; i >= 0; i = (i & (i + 1)) - 1) {
            res += dat[i];
        }
        return res;
    }
    T sum(int l, int r) const {
        return sum(r - 1) - sum(l - 1);
    }

private:
    const int n;
    vector<T> dat;
};

pair<ld, ll> decomp(ld val) {
    int cnt = 0;
    while(val >= 10.0) {
        cnt += 1;
        val /= 10;
    }
    return make_pair(val, cnt);
}

int main() {
    ios_base::sync_with_stdio(false); cin.tie(0);

    int n, m; cin >> n >> m;
    vector<ll> a(n), b(m);
    for(auto& x : a) cin >> x;
    for(auto& x : b) cin >> x;

    fenwick_tree<ll> sum_b(m + 1);
    vector<pair<ld, int>> bs(m);
    for(int i = 0; i < m; ++i) {
        auto p = decomp(b[i]);
        sum_b.add(i, p.second + 1);
        bs[i] = make_pair(p.first, i);
    }
    sort(bs.begin(), bs.end());

    vector<ll> sum(n + 1);
    vector<pair<ld, ll>> aval(n);
    for(int i = 0; i < n; ++i) {
        auto p = decomp(a[i]);
        aval[i] = p;
        sum[i + 1] = sum[i] + p.second * m + sum_b.sum(0, m);
        sum[i + 1] += bs.end() - lower_bound(bs.begin(), bs.end(), make_pair(10.0L / p.first, -1));
    }
    reverse(bs.begin(), bs.end());

    int q; cin >> q;
    vector<ll> d(q), aidx(q);
    string ans(q, ' ');
    for(int i = 0; i < q; ++i) {
        cin >> d[i];
        int lb = 0, ub = n + 1;
        while(ub - lb > 1) {
            const int mid = (ub + lb) / 2;
            (sum[mid] >= d[i] ? ub : lb) = mid;
        }
        if(ub == n + 1) {
            ans[i] = 'x';
        } else {
            aidx[i] = lb;
        }
    }
    vector<int> qord(q);
    iota(qord.begin(), qord.end(), 0);
    sort(qord.begin(), qord.end(), [&] (int i, int j) { return aval[aidx[i]].first < aval[aidx[j]].first; });

    int b_it = 0;
    for(auto const qi : qord) {
        if(ans[qi] == 'x') continue;
        const int ai = aidx[qi];
        while(b_it < m && bs[b_it].first * aval[ai].first >= 10.0L) {
            sum_b.add(bs[b_it++].second, 1);
        }
        ll lb = 0, ub = m;
        while(ub - lb > 1) {
            const int mid = (lb + ub) / 2;
            const ll s = sum[ai] + sum_b.sum(0, mid) + aval[ai].second * mid;
            (s >= d[qi] ? ub : lb) = mid;
        }
        const ll offset = d[qi] - (sum[ai] + sum_b.sum(0, lb) + aval[ai].second * lb);
        ans[qi] = to_string(a[ai] * b[lb])[offset - 1];
    }

    cout << ans << endl;
}
accuracy: 1
time_ms: 210
memory_kb: 18820
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, s, t) for (int i = (int)(s); i < (int)(t); ++i)
#define revrep(i, t, s) for (int i = (int)(t)-1; i >= (int)(s); --i)
#define all(x) begin(x), end(x)
template <typename T> bool chmax(T& a, const T& b) { return a < b ? (a = b, 1) : 0; }
template <typename T> bool chmin(T& a, const T& b) { return a > b ? (a = b, 1) : 0; }


template <typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
    for (int i = 0; i < (int) v.size(); ++i) os << v[i] << " ";
    return os;
}


int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(15);

    int N, M;
    cin>>N>>M;
    vector<ll> a(N), b(M);
    for(auto&x:a)cin>>x;
    for(auto&x:b)cin>>x;
    int Q;
    cin>>Q;
    vector<ll> d(Q);
    for(auto& x : d)cin>>x,--x;

    auto sumdigit = [&](const vector<ll>& ys, ll x){
        ll ans = 0;
        int k = 0;
        ll p = 1;
        rep(d,1,19){
            p *= 10;
            ll y = (p-1)/x;
            int nk = upper_bound(ys.begin()+k, ys.end(), y) - ys.begin();
            ans += (nk - k)*d;
            k = nk;
        }
        ans += (ys.size() - k)*19;
        return ans;
    };

    auto bsort = b;
    sort(all(bsort));
    vector<ll> rowcnt(N);
    rep(i,0,N) rowcnt[i] = sumdigit(bsort, a[i]);
    vector<ll> cumrow(N+1);
    rep(i,0,N) cumrow[i+1] = cumrow[i] + rowcnt[i];


    vector<int> row(Q);
    vector<int> qs;
    rep(i,0,Q){
        row[i] = upper_bound(all(cumrow), d[i]) - cumrow.begin();
        --row[i];
        if (row[i] < N){
            qs.push_back(i);
            d[i] -= cumrow[row[i]];
        }
    }
    string ans(Q, 'x');
    auto dfs = [&](auto& dfs, int l, int r, const vector<int>& qs) {
        if (r - l == 1) {
            for (int q : qs){
                string s = to_string(a[row[q]] * b[l]);
                ans[q] = s[d[q]];
            }
            return;
        }
        int m = (l+r)/2;
        vector<ll> bsort(b.begin()+l, b.begin()+m);
        sort(all(bsort));
        vector<int> left, right;
        for(int q:qs){
            ll x = sumdigit(bsort, a[row[q]]);
            if(d[q] < x){
                left.push_back(q);
            }else{
                d[q] -= x;
                right.push_back(q);
            }
        }
        dfs(dfs, l, m, left);
        dfs(dfs, m, r, right);
    };

    dfs(dfs, 0, M, qs);
    cout << ans << endl;
}
accuracy: 1
time_ms: 1630
memory_kb: 16388
final_rank: 13

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
using ll = long long;


template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b)a=b;};
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b)a=b;};

template<typename T> void drop(T x){cout<<x<<endl;exit(0);};

template<typename T, typename E>
struct SegmentTree{
  using F = function<T(T ,T)>;
  using G = function<T(T, E)>;
  using H = function<E(E, E)>;

  Int n, height;
  F f;
  G g;
  H h;
  T ti;
  E ei;
  vector<T> dat;
  vector<E> laz;

  SegmentTree(F f, G g, H h, T ti, E ei):
    f(f), g(g), h(h), ti(ti), ei(ei){}

  void init(Int n_){
    n = 1; height = 0;
    while(n < n_) n<<=1, height++;
    dat.assign(2*n, ti);
    laz.assign(2*n, ei);
  }

  void build(const vector<T> &v){
    Int n_ = v.size();
    init(n_);
    for(Int i=0;i<n_;i++) dat[n+i] = v[i];
    for(Int i=n-1;i;i--)
      dat[i] = f(dat[(i<<1)|0], dat[(i<<1)|1]);
  }

  inline T reflect(Int k){
    return laz[k] == ei? dat[k]:g(dat[k], laz[k]);
  }

  inline void eval(Int k){
    if(laz[k] == ei) return;
    laz[(k<<1)|0] = h(laz[(k<<1)|0], laz[k]);
    laz[(k<<1)|1] = h(laz[(k<<1)|1], laz[k]);
    dat[k] = reflect(k);
    laz[k] = ei;
  }

  inline void thrust(Int k){
    for(Int i=height;i;i--) eval(k>>i);
  }

  inline void recalc(Int k){
    while(k>>=1)
      dat[k] = f(reflect((k<<1)|0), reflect((k<<1)|1));
  }

  void update(Int a, Int b, E x){
    thrust(a += n);
    thrust(b += n-1);
    for(Int l=a, r=b+1;l<r;l>>=1, r>>=1){
      if(l&1) laz[l] = h(laz[l], x), l++;
      if(r&1) --r, laz[r] = h(laz[r], x);
    }
    recalc(a);
    recalc(b);
  }

  void set_val(Int a, T x){
    thrust(a += n);
    dat[a] = x; laz[a] = ei;
    recalc(a);
  }

  T query(Int a, Int b){
    thrust(a += n);
    thrust(b += n-1);
    T vl = ti, vr = ti;
    for(Int l=a, r=b+1;l<r;l>>=1, r>>=1){
      if(l&1) vl = f(vl, reflect(l++));
      if(r&1) vr = f(reflect(--r), vr);
    }
    return f(vl, vr);
  }

  template<typename C>
  Int find(Int st, C &check, T &acc, Int k, Int l, Int r){
    if(l + 1 == r){
      acc = f(acc, reflect(k));
      return check(acc)? k-n:-1;
    }
    eval(k);
    Int m = (l+r)>>1;
    if(m<=st) return find(st, check, acc, (k<<1)|1, m, r);

    if(st <= l && !check(f(acc, dat[k]))){
      acc = f(acc, dat[k]);
      return -1;
    }

    Int vl = find(st, check, acc, (k<<1)|0, l, m);
    if(~vl) return vl;
    return find(st, check, acc, (k<<1)|1, m, r);
  }

  template<typename C>
  Int find(Int st, C &check){
    T acc = ti;
    return find(st, check, acc, 1, 0, n);
  }
};


const Int MAX = 1e5+100;
Int dp[20][MAX];

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  Int n,m;
  cin>>n>>m;
  vector<Int> as(n),bs(m);
  for(Int i=0;i<n;i++) cin>>as[i];
  for(Int i=0;i<m;i++) cin>>bs[i];

  Int q;
  cin>>q;
  vector<Int> ds(q);
  for(Int i=0;i<q;i++) cin>>ds[i];

  string ans(q,'x');

  vector<Int> ss(bs);
  sort(ss.begin(),ss.end());

  for(Int i=0;i<n;i++){
    Int po=1;
    for(Int j=0;j<19;j++){
      auto pred=[&](Int x){return as[i]*x<po;};
      Int L=-1,R=m;
      while(L+1<R){
        Int M=(L+R)>>1;
        if(pred(ss[M])) L=M;
        else R=M;
      }
      dp[j][i]=R;
      if(j<18) po*=10;
    }

    dp[19][i]=m;
  }

  vector<Int> sm(n+1,0);
  for(Int i=0;i<n;i++){
    Int res=0;
    for(Int j=1;j<20;j++)
      res+=(dp[j][i]-dp[j-1][i])*j;
    sm[i+1]=sm[i]+res;
  }

  // sm[k] <= ds[i]
  vector< vector<Int> > I(n+2);
  for(Int i=0;i<q;i++){
    ds[i]--;
    Int k=upper_bound(sm.begin(),sm.end(),ds[i])-sm.begin()-1;
    //cout<<k<<endl;
    I[k].emplace_back(i);
  }

  using P = pair<Int, Int>;
  vector<P> vp,vq;
  for(Int i=0;i<n;i++) vp.emplace_back(as[i],i);
  for(Int i=0;i<m;i++) vq.emplace_back(bs[i],i);
  sort(vp.begin(),vp.end());
  sort(vq.rbegin(),vq.rend());

  auto f=[&](Int a,Int b){return a+b;};
  SegmentTree<Int, Int> seg(f,f,f,0,0);
  seg.build(vector<Int>(m+1,0));

  vector<Int> pos(20,0);
  for(Int i=0;i<n;i++){
    Int k=vp[i].second;

    Int po=1;
    for(Int j=0;j<19;j++){
      while((pos[j]<m)&&(vq[pos[j]].first*as[k]>=po)){
        Int q=vq[pos[j]].second;
        seg.set_val(q,j+1);
        pos[j]++;
      }
      if(j<18) po*=10;
    }

    for(Int j:I[k]){
      Int d=ds[j]-sm[k];
      // [0, p) <= d
      // [0, p] > d
      auto check=[&](Int s){return s>d;};
      Int p=seg.find(0,check);
      Int r=seg.query(0,p);
      assert(seg.query(0,p+0)<=d);
      assert(seg.query(0,p+1)> d);
      //cout<<d<<" "<<seg.query(0,p)<<" "<<seg.query(0,p+1)<<endl;
      d-=r;
      //cout<<j<<" "<<d<<":"<<to_string(as[k]*bs[p])<<endl;
      ans[j]=to_string(as[k]*bs[p])[d];
    }
  }

  cout<<ans<<endl;
  return 0;
}
accuracy: 1
time_ms: 440
memory_kb: 39736
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, s, t) for (int i = (int)(s); i < (int)(t); ++i)
#define revrep(i, t, s) for (int i = (int)(t)-1; i >= (int)(s); --i)
#define all(x) begin(x), end(x)
template <typename T> bool chmax(T& a, const T& b) { return a < b ? (a = b, 1) : 0; }
template <typename T> bool chmin(T& a, const T& b) { return a > b ? (a = b, 1) : 0; }


template <typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
    for (int i = 0; i < (int) v.size(); ++i) os << v[i] << " ";
    return os;
}


int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(15);

    int N, M;
    cin>>N>>M;
    vector<ll> a(N), b(M);
    for(auto&x:a)cin>>x;
    for(auto&x:b)cin>>x;
    int Q;
    cin>>Q;
    vector<ll> d(Q);
    for(auto& x : d)cin>>x,--x;

    auto sumdigit = [&](const vector<ll>& ys, ll x){
        ll ans = 0;
        int k = 0;
        ll p = 1;
        rep(d,1,19){
            p *= 10;
            ll y = (p-1)/x;
            int nk = upper_bound(ys.begin()+k, ys.end(), y) - ys.begin();
            ans += (nk - k)*d;
            k = nk;
        }
        ans += (ys.size() - k)*19;
        return ans;
    };

    auto bsort = b;
    sort(all(bsort));
    vector<ll> rowcnt(N);
    rep(i,0,N) rowcnt[i] = sumdigit(bsort, a[i]);
    vector<ll> cumrow(N+1);
    rep(i,0,N) cumrow[i+1] = cumrow[i] + rowcnt[i];


    vector<int> row(Q);
    vector<int> qs;
    rep(i,0,Q){
        row[i] = upper_bound(all(cumrow), d[i]) - cumrow.begin();
        --row[i];
        if (row[i] < N){
            qs.push_back(i);
            d[i] -= cumrow[row[i]];
        }
    }
    string ans(Q, 'x');
    auto dfs = [&](auto& dfs, int l, int r, const vector<int>& qs) {
        if (r - l == 1) {
            for (int q : qs){
                string s = to_string(a[row[q]] * b[l]);
                ans[q] = s[d[q]];
            }
            return;
        }
        int m = (l+r)/2;
        vector<ll> bsort(b.begin()+l, b.begin()+m);
        sort(all(bsort));
        vector<int> left, right;
        for(int q:qs){
            ll x = sumdigit(bsort, a[row[q]]);
            if(d[q] < x){
                left.push_back(q);
            }else{
                d[q] -= x;
                right.push_back(q);
            }
        }
        dfs(dfs, l, m, left);
        dfs(dfs, m, r, right);
    };

    dfs(dfs, 0, M, qs);
    cout << ans << endl;
}
accuracy: 1
time_ms: 1640
memory_kb: 16588
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, s, t) for (int i = (int)(s); i < (int)(t); ++i)
#define revrep(i, t, s) for (int i = (int)(t)-1; i >= (int)(s); --i)
#define all(x) begin(x), end(x)
template <typename T> bool chmax(T& a, const T& b) { return a < b ? (a = b, 1) : 0; }
template <typename T> bool chmin(T& a, const T& b) { return a > b ? (a = b, 1) : 0; }


template <typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
    for (int i = 0; i < (int) v.size(); ++i) os << v[i] << " ";
    return os;
}


int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(15);

    int N, M;
    cin>>N>>M;
    vector<ll> a(N), b(M);
    for(auto&x:a)cin>>x;
    for(auto&x:b)cin>>x;
    int Q;
    cin>>Q;
    vector<ll> d(Q);
    for(auto& x : d)cin>>x,--x;

    auto sumdigit = [&](const vector<ll>& ys, ll x){
        ll ans = 0;
        int k = 0;
        ll p = 1;
        rep(d,1,19){
            p *= 10;
            ll y = (p-1)/x;
            int nk = upper_bound(ys.begin()+k, ys.end(), y) - ys.begin();
            ans += (nk - k)*d;
            k = nk;
        }
        return ans;
    };

    auto bsort = b;
    sort(all(bsort));
    vector<ll> rowcnt(N);
    rep(i,0,N) rowcnt[i] = sumdigit(bsort, a[i]);
    vector<ll> cumrow(N+1);
    rep(i,0,N) cumrow[i+1] = cumrow[i] + rowcnt[i];


    vector<int> row(Q);
    vector<int> qs;
    rep(i,0,Q){
        row[i] = upper_bound(all(cumrow), d[i]) - cumrow.begin();
        --row[i];
        if (row[i] < N){
            qs.push_back(i);
            d[i] -= cumrow[row[i]];
        }
    }
    string ans(Q, 'x');
    auto dfs = [&](auto& dfs, int l, int r, const vector<int>& qs) {
        if (r - l == 1) {
            for (int q : qs){
                string s = to_string(a[row[q]] * b[l]);
                ans[q] = s[d[q]];
            }
            return;
        }
        int m = (l+r)/2;
        vector<ll> bsort(b.begin()+l, b.begin()+m);
        sort(all(bsort));
        vector<int> left, right;
        for(int q:qs){
            ll x = sumdigit(bsort, a[row[q]]);
            if(d[q] < x){
                left.push_back(q);
            }else{
                d[q] -= x;
                right.push_back(q);
            }
        }
        dfs(dfs, l, m, left);
        dfs(dfs, m, r, right);
    };

    dfs(dfs, 0, M, qs);
    cout << ans << endl;
}
accuracy: 0.9264705882352942
time_ms: 1520
memory_kb: 16824
final_rank: 16

code_snippet: #pragma GCC optimize("O3")
#include <bits/stdc++.h>

using namespace std;
#define rep(i, x) for(int i = 0; i < (x); i++)
using ll = long long;
#define all(v) v.begin(), v.end()

struct Dinic {
	struct Edge {
		int to, rev;
		ll c, oc;
		ll flow() { return max(oc - c, 0ll); }
	};
	vector<int> lvl, ptr, q;
	vector<vector<Edge>> adj;
	Dinic(int n) : lvl(n), ptr(n), q(n), adj(n) {}
	void add_edge(int a, int b, ll c, ll rcap = 0) {
		adj[a].push_back({b, (int)adj[b].size(), c, c});
		adj[b].push_back({a, (int)adj[a].size() - 1, rcap, rcap});
	}
	ll dfs(int v, int t, ll f) {
		if(v == t or !f) return f;
		for(int &i = ptr[v]; i < (int)adj[v].size(); i++) {
			Edge &e = adj[v][i];
			if(lvl[e.to] == lvl[v] + 1) {
				if(ll p = dfs(e.to, t, min(f, e.c))) {
					e.c -= p, adj[e.to][e.rev].c += p;
					return p;
				}
			}
		}
		return 0;
	}
	ll calc(int s, int t) {
		ll flow = 0;
		q[0] = s;
		rep(L, 31) do {
			lvl = ptr = vector<int>(q.size());
			int qi = 0, qe = lvl[s] = 1;
			while(qi < qe and !lvl[t]) {
				int v = q[qi++];
				for(Edge e : adj[v]) {
					if(!lvl[e.to] and e.c >> (30 - L)) {
						q[qe++] = e.to, lvl[e.to] = lvl[v] + 1;
					}
				}
			}
			while(ll p = dfs(s, t, LLONG_MAX)) flow += p;
		}
		while(lvl[t])
			;
		return flow;
	}
};

struct uf {
	vector<int> par;
	uf(int n) : par(n, -1) {}
	int root(int x) {
		if(par[x] < 0) return x;
		return par[x] = root(par[x]);
	}
	bool same(int x, int y) { return root(x) == root(y); }
	bool unite(int x, int y) {
		x = root(x), y = root(y);
		if(x == y) return false;
		if(par[x] > par[y]) swap(x, y);
		par[x] += par[y];
		par[y] = x;
		return true;
	}
	int size(int x) { return -par[root(x)]; }
};

typedef complex<double> C;
typedef vector<double> vd;

void fft(vector<C> &a) {
	int n = a.size(), L = 31 - __builtin_clz(n);
	static vector<complex<long double>> R(2, 1);
	static vector<C> rt(2, 1);
	for(static int k = 2; k < n; k *= 2) {
		R.resize(n);
		rt.resize(n);
		auto x = polar(1.0L, acos(-1.0L) / k);
		for(int i = k; i < 2 * k; i++) rt[i] = R[i] = i & 1 ? R[i / 2] * x : R[i / 2];
	}
	vector<int> rev(n);
	rep(i, n) rev[i] = (rev[i / 2] | (i & 1) << L) / 2;
	rep(i, n) if(i < rev[i]) swap(a[i], a[rev[i]]);
	for(int k = 1; k < n; k *= 2) {
		for(int i = 0; i < n; i += 2 * k) {
			rep(j, k) {
				auto x = (double *)&rt[j + k], y = (double *)&a[i + j + k];
				C z(x[0] * y[0] - x[1] * y[1], x[0] * y[1] + x[1] * y[0]);
				a[i + j + k] = a[i + j] - z;
				a[i + j] += z;
			}
		}
	}
}

vector<double> conv(vector<double> a, vector<double> b) {
	vector<double> res(a.size() + b.size() - 1);
	int L = 32 - __builtin_clz(res.size()), n = 1 << L;
	vector<C> in(n), out(n);
	copy(all(a), begin(in));
	rep(i, b.size()) in[i].imag(b[i]);
	fft(in);
	for(C &x : in) x *= x;
	rep(i, n) out[i] = in[-i & (n - 1)] - conj(in[i]);
	fft(out);
	rep(i, res.size()) res[i] = imag(out[i]) / (4 * n);
	return res;
}

struct ft {
	vector<ll> s;
	int n;
	ft(int n) : s(n), n(n) {}
	void add(int p, int c = 1) {
		for(; p < s.size(); p |= p + 1) s[p] += c;
	}
	ll sum(int p) {
		ll res = 0;
		for(; p > 0; p &= p - 1) res += s[p - 1];
		return res;
	}
	ll sum(int l, int r) {
		return sum(r) - sum(l);
	}
};

int main() {
	int n, m;
	cin >> n >> m;
	vector<ll> a(n), b(m);
	rep(i, n) cin >> a[i];
	rep(i, m) cin >> b[i];
	auto cb = b;
	set<ll> xp;
	for(auto v : b) xp.insert(v);

	rep(i, n) {
		for(ll j = 0, d = 1; j <= 18; j++, d *= 10) {
			ll u = (d + a[i] - 1) / a[i];
			if(u <= 1000000000) xp.insert(u);
		}
	}

	map<int, int> id;
	int sz = 0;
	for(auto v : xp) id[v] = sz++;
	ft bt(sz);
	rep(i, m) b[i] = id[b[i]];
	rep(i, m) {
		bt.add(b[i], 1);
	}
	vector<ll> ds(n);
	vector<int> a_len(n);
	rep(i, n) a_len[i] = to_string(a[i]).size();
	vector<vector<int>> us(n, vector(19, -1));
	rep(i, n) {
		for(ll j = 0, d = 1; j <= 18; j++, d *= 10) {
			ll u = (d + a[i] - 1) / a[i];
			if(u <= 1000000000) {
				us[i][j] = id[u];
				if(us[i][j] == -1) break;
				ds[i] += bt.sum(us[i][j], sz);
			}
		}
	}

	vector<ll> cum_d(n + 1);
	rep(i, n) cum_d[i + 1] = cum_d[i] + ds[i];

	int q;
	cin >> q;
	vector<ll> d(q);
	for(auto &v : d) cin >> v;

	string res;
	rep(i, q) res.push_back('x');
	vector mid(m, vector(0, 0));

	vector hei(q, -1);
	vector cnt(q, 0ll);
	rep(i, q) {
		if(d[i] <= cum_d.back()) {
			int ok = 0, ng = n;
			while(abs(ok - ng) > 1) {
				int mid = (ok + ng) / 2;
				if(cum_d[mid] < d[i])
					ok = mid;
				else
					ng = mid;
			}
			hei[i] = ok;
			cnt[i] = d[i] - cum_d[ok];
		}
	}
	vector ok(q, -1), ng(q, m - 1);
	rep(i, q) {
		if(d[i] <= cum_d.back()) {
			if(abs(ng[i] - ok[i]) > 1) {
				int md = (ok[i] + ng[i]) / 2;
				mid[md].push_back(i);
			}
		}
	}

	while(true) {
		bool fin = true;
		bt = ft(sz);
		vector nmid(m, vector(0, 0));

		rep(i, m) {
			bt.add(b[i]);
			ll all_sum = bt.sum(sz);
			for(auto idx : mid[i]) {
				ll sm = a_len[hei[idx]] * (i + 1);
				for(int j = a_len[hei[idx]]; j <= min(a_len[hei[idx]] + 9, 18); j++) {
					if(us[hei[idx]][j] == -1) break;
					sm += all_sum - bt.sum(us[hei[idx]][j]);
				}
				if(sm < cnt[idx])
					ok[idx] = i;
				else
					ng[idx] = i;
				if(abs(ok[idx] - ng[idx]) > 1) {
					fin = false;
					int md = (ok[idx] + ng[idx]) / 2;
					nmid[md].push_back(idx);
				}
			}
		}
		if(fin) break;
		mid = nmid;
	}

	vector oks(m, vector(0, 0));
	rep(i, q) {
		if(hei[i] != -1) {
			if(ok[i] != -1) {
				oks[ok[i]].push_back(i);
			}
		}
	}
	bt = ft(sz);
	rep(i, m) {
		bt.add(b[i]);
		for(auto idx : oks[i]) {
			ll sm = 0;
			rep(j, 19) {
				if(us[hei[idx]][j] == -1) break;
				sm += bt.sum(us[hei[idx]][j], sz);
			}
			cnt[idx] -= sm;
		}
	}

	rep(i, q) {
		if(hei[i] != -1) {
			int h = hei[i], w = ok[i] + 1, c = cnt[i];
			string s = to_string(a[h] * cb[w]);
			res[i] = s[c - 1];
		}
	}

	cout << res << endl;
}
accuracy: 1
time_ms: 1790
memory_kb: 90924
final_rank: 15

code_snippet: #pragma GCC optimize("O3")
#include <bits/stdc++.h>

using namespace std;
#define rep(i, x) for(int i = 0; i < (x); i++)
using ll = long long;
#define all(v) v.begin(), v.end()

struct Dinic {
	struct Edge {
		int to, rev;
		ll c, oc;
		ll flow() { return max(oc - c, 0ll); }
	};
	vector<int> lvl, ptr, q;
	vector<vector<Edge>> adj;
	Dinic(int n) : lvl(n), ptr(n), q(n), adj(n) {}
	void add_edge(int a, int b, ll c, ll rcap = 0) {
		adj[a].push_back({b, (int)adj[b].size(), c, c});
		adj[b].push_back({a, (int)adj[a].size() - 1, rcap, rcap});
	}
	ll dfs(int v, int t, ll f) {
		if(v == t or !f) return f;
		for(int &i = ptr[v]; i < (int)adj[v].size(); i++) {
			Edge &e = adj[v][i];
			if(lvl[e.to] == lvl[v] + 1) {
				if(ll p = dfs(e.to, t, min(f, e.c))) {
					e.c -= p, adj[e.to][e.rev].c += p;
					return p;
				}
			}
		}
		return 0;
	}
	ll calc(int s, int t) {
		ll flow = 0;
		q[0] = s;
		rep(L, 31) do {
			lvl = ptr = vector<int>(q.size());
			int qi = 0, qe = lvl[s] = 1;
			while(qi < qe and !lvl[t]) {
				int v = q[qi++];
				for(Edge e : adj[v]) {
					if(!lvl[e.to] and e.c >> (30 - L)) {
						q[qe++] = e.to, lvl[e.to] = lvl[v] + 1;
					}
				}
			}
			while(ll p = dfs(s, t, LLONG_MAX)) flow += p;
		}
		while(lvl[t])
			;
		return flow;
	}
};

struct uf {
	vector<int> par;
	uf(int n) : par(n, -1) {}
	int root(int x) {
		if(par[x] < 0) return x;
		return par[x] = root(par[x]);
	}
	bool same(int x, int y) { return root(x) == root(y); }
	bool unite(int x, int y) {
		x = root(x), y = root(y);
		if(x == y) return false;
		if(par[x] > par[y]) swap(x, y);
		par[x] += par[y];
		par[y] = x;
		return true;
	}
	int size(int x) { return -par[root(x)]; }
};

typedef complex<double> C;
typedef vector<double> vd;

void fft(vector<C> &a) {
	int n = a.size(), L = 31 - __builtin_clz(n);
	static vector<complex<long double>> R(2, 1);
	static vector<C> rt(2, 1);
	for(static int k = 2; k < n; k *= 2) {
		R.resize(n);
		rt.resize(n);
		auto x = polar(1.0L, acos(-1.0L) / k);
		for(int i = k; i < 2 * k; i++) rt[i] = R[i] = i & 1 ? R[i / 2] * x : R[i / 2];
	}
	vector<int> rev(n);
	rep(i, n) rev[i] = (rev[i / 2] | (i & 1) << L) / 2;
	rep(i, n) if(i < rev[i]) swap(a[i], a[rev[i]]);
	for(int k = 1; k < n; k *= 2) {
		for(int i = 0; i < n; i += 2 * k) {
			rep(j, k) {
				auto x = (double *)&rt[j + k], y = (double *)&a[i + j + k];
				C z(x[0] * y[0] - x[1] * y[1], x[0] * y[1] + x[1] * y[0]);
				a[i + j + k] = a[i + j] - z;
				a[i + j] += z;
			}
		}
	}
}

vector<double> conv(vector<double> a, vector<double> b) {
	vector<double> res(a.size() + b.size() - 1);
	int L = 32 - __builtin_clz(res.size()), n = 1 << L;
	vector<C> in(n), out(n);
	copy(all(a), begin(in));
	rep(i, b.size()) in[i].imag(b[i]);
	fft(in);
	for(C &x : in) x *= x;
	rep(i, n) out[i] = in[-i & (n - 1)] - conj(in[i]);
	fft(out);
	rep(i, res.size()) res[i] = imag(out[i]) / (4 * n);
	return res;
}

struct ft {
	vector<ll> s;
	int n;
	ft(int n) : s(n), n(n) {}
	void add(int p, int c = 1) {
		for(; p < s.size(); p |= p + 1) s[p] += c;
	}
	ll sum(int p) {
		ll res = 0;
		for(; p > 0; p &= p - 1) res += s[p - 1];
		return res;
	}
	ll sum(int l, int r) {
		return sum(r) - sum(l);
	}
};

int main() {
	int n, m;
	cin >> n >> m;
	vector<ll> a(n), b(m);
	rep(i, n) cin >> a[i];
	rep(i, m) cin >> b[i];
	auto cb = b;
	set<ll> xp;
	for(auto v : b) xp.insert(v);

	rep(i, n) {
		for(ll j = 0, d = 1; j <= 18; j++, d *= 10) {
			ll u = (d + a[i] - 1) / a[i];
			if(u <= 1000000000) xp.insert(u);
		}
	}

	map<int, int> id;
	int sz = 0;
	for(auto v : xp) id[v] = sz++;
	ft bt(sz);
	rep(i, m) b[i] = id[b[i]];
	rep(i, m) {
		bt.add(b[i], 1);
	}
	vector<ll> ds(n);
	vector<int> a_len(n);
	rep(i, n) a_len[i] = to_string(a[i]).size();
	vector<vector<int>> us(n, vector(19, -1));
	rep(i, n) {
		for(ll j = 0, d = 1; j <= 18; j++, d *= 10) {
			ll u = (d + a[i] - 1) / a[i];
			if(u <= 1000000000) {
				us[i][j] = id[u];
				if(us[i][j] == -1) break;
				ds[i] += bt.sum(us[i][j], sz);
			}
		}
	}

	vector<ll> cum_d(n + 1);
	rep(i, n) cum_d[i + 1] = cum_d[i] + ds[i];

	int q;
	cin >> q;
	vector<ll> d(q);
	for(auto &v : d) cin >> v;

	string res;
	rep(i, q) res.push_back('x');
	vector mid(m, vector(0, 0));

	vector hei(q, -1);
	vector cnt(q, 0ll);
	rep(i, q) {
		if(d[i] <= cum_d.back()) {
			int ok = 0, ng = n;
			while(abs(ok - ng) > 1) {
				int mid = (ok + ng) / 2;
				if(cum_d[mid] < d[i])
					ok = mid;
				else
					ng = mid;
			}
			hei[i] = ok;
			cnt[i] = d[i] - cum_d[ok];
		}
	}
	vector ok(q, -1), ng(q, m - 1);
	rep(i, q) {
		if(d[i] <= cum_d.back()) {
			if(abs(ng[i] - ok[i]) > 1) {
				int md = (ok[i] + ng[i]) / 2;
				mid[md].push_back(i);
			}
		}
	}

	while(true) {
		bool fin = true;
		bt = ft(sz);
		vector nmid(m, vector(0, 0));

		rep(i, m) {
			bt.add(b[i]);
			ll all_sum = bt.sum(sz);
			for(auto idx : mid[i]) {
				ll sm = a_len[hei[idx]] * (i + 1);
				for(int j = a_len[hei[idx]]; j <= a_len[hei[idx]] + 9; j++) {
					if(us[hei[idx]][j] == -1) break;
					sm += all_sum - bt.sum(us[hei[idx]][j]);
				}
				if(sm < cnt[idx])
					ok[idx] = i;
				else
					ng[idx] = i;
				if(abs(ok[idx] - ng[idx]) > 1) {
					fin = false;
					int md = (ok[idx] + ng[idx]) / 2;
					nmid[md].push_back(idx);
				}
			}
		}
		if(fin) break;
		mid = nmid;
	}

	vector oks(m, vector(0, 0));
	rep(i, q) {
		if(hei[i] != -1) {
			if(ok[i] != -1) {
				oks[ok[i]].push_back(i);
			}
		}
	}
	bt = ft(sz);
	rep(i, m) {
		bt.add(b[i]);
		for(auto idx : oks[i]) {
			ll sm = 0;
			rep(j, 19) {
				if(us[hei[idx]][j] == -1) break;
				sm += bt.sum(us[hei[idx]][j], sz);
			}
			cnt[idx] -= sm;
		}
	}

	rep(i, q) {
		if(hei[i] != -1) {
			int h = hei[i], w = ok[i] + 1, c = cnt[i];
			string s = to_string(a[h] * cb[w]);
			res[i] = s[c - 1];
		}
	}

	cout << res << endl;
}
accuracy: 0.9264705882352942
time_ms: 1850
memory_kb: 90992
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
template<class T> void chmax(T& a, T b){ if(a < b) a = b; }


template<class T>
struct SegmentTree{
    virtual T f(const T&, const T&) const = 0;
    const T def_value;
    ll size = 1, rank = 0, expected_size;
    vector<T> data;
    SegmentTree(ll n, const T& def_value): def_value(def_value), expected_size(n){
        while(size < expected_size){
            size *= 2;
            rank++;
        }
        data.assign(size * 2, def_value);
    }
    SegmentTree(const vector<T>& v, const T& def_value): def_value(def_value), expected_size(v.size()){
        while(size < expected_size){
            size *= 2;
            rank++;
        }
        data.assign(size * 2, def_value);
        for(ll i = 0; i < v.size(); i++) data[size + i] = v[i];
        // for(ll i = Base::size; --i;) Base::data[i] = f(Base::data[i * 2], Base::data[i * 2 + 1]);
    }
    T operator[](ll at) const {
        return data[size + at];
    }
    void update(ll at){
        while(at /= 2) data[at] = f(data[at * 2], data[at * 2 + 1]);
    }
    void set(ll at, const T& val){
        at += size;
        data[at] = val;
        update(at);
    }
    void add(ll at, const T& val){
        at += size;
        data[at] += val;
        update(at);
    }
    T get(ll l, ll r) const {
        T L = def_value, R = def_value;
        l += size; r += size;
        for(; l < r; l /= 2, r /= 2){
            if(l & 1) L = f(L, data[l++]);
            if(r & 1) R = f(data[--r], R);
        }
        return f(L, R);
    }
    template<class F> ll find_last(const F& check, ll l = 0) const { // max x  s.t. check(get(l, x)) == true
        if(l == expected_size) return expected_size;
        ll height = 0, at = l + size;
        T val = def_value;
        for(; height <= rank; height++) if(at >> height & 1){
            T val2 = f(val, data[at >> height]);
            if(check(val2)){
                at += 1 << height;
                if(at == size * 2) return expected_size;
                val = val2;
            }
            else break;
        }
        for(; height--; ){
            T val2 = f(val, data[at >> height]);
            if(check(val2)){
                at += 1 << height;
                if(at == size * 2) return expected_size;
                val = val2;
            }
        }
        return min(at - size, expected_size);
    }
    template<class F> ll find_first(const F& check, ll r) const { // min x  s.t. check(get(x, r)) == true
        if(!r) return 0;
        ll height = 0, at = r + size;
        T val = def_value;
        for(; height <= rank; height++) if(at >> height & 1){
            T val2 = f(val, data[at >> height ^ 1]);
            if(check(val2)){
                at -= 1 << height;
                if(at == size) return 0;
                val = val2;
            }
            else break;
        }
        for(; height--; ){
            T val2 = f(val, data[(at >> height) - 1]);
            if(check(val2)){
                at -= 1 << height;
                if(at == size) return 0;
                val = val2;
            }
        }
        return at - size;
    }
    void clear(){
        for(auto& i : data) i = def_value;
    }
};
template<class T>
struct RSQ : SegmentTree<T>{
    using Base = SegmentTree<T>;
    T f(const T& a, const T& b) const {return a + b;}
    RSQ(ll n, const T& def_value = T()) : Base(n, def_value){}
    RSQ(const vector<T>& v, const T& def_value = T()) : Base(v, def_value){
        for(ll i = Base::size; --i;) Base::data[i] = f(Base::data[i * 2], Base::data[i * 2 + 1]);
    }
};
int main(){
    ll N, M;
    cin >> N >> M;
    vector<ll> A(N), B(M);
    for(ll& a : A) cin >> a;
    for(ll& b : B) cin >> b;
    vector<ll> digit(N, M);
    {
        vector<ll> b = B;
        sort(b.begin(), b.end());
        for(ll i = 0; i < N; i++){
            const ll a = A[i];
            for(ll x = 10; ; x *= 10){
                digit[i] += b.end() - lower_bound(b.begin(), b.end(), (x + a - 1) / a);
                if(x == (ll)1e18)break;
            }
        }
    }
    digit.insert(digit.begin(), 0);
    for(ll i = 0; i < N; i++) digit[i + 1] += digit[i];
    ll Q;
    cin >> Q;
    vector<array<ll, 3>> query(Q);
    for(auto& [x, y, d] : query){
        cin >> d;
        auto p = --lower_bound(digit.begin(), digit.end(), d);
        d -= *p;
        x = p - digit.begin();
    }
    vector<ll> idx;
    for(ll i = 0; i < Q; i++) if(query[i][0] != N) idx.push_back(i);
    sort(idx.begin(), idx.end(), [&](ll x, ll y){ return A[query[x][0]] < A[query[y][0]]; });
    RSQ<ll> seg(vector<ll>(M, 1));
    vector<pair<ll, ll>> b(M);
    for(ll i = 0; i < M; i++) b[i] = {B[i], i};
    sort(b.begin(), b.end(), greater<>{});
    vector<ll> dig_at(19);
    string ans(Q, 'x');
    for(ll i : idx){
        auto& [x, y, d] = query[i];
        {
            const ll a = A[x];
            for(ll i = 1, x = 10; i <= 18; i++, x *= 10){
                ll& at = dig_at[i];
                while(at < M && a * b[at].first >= x){
                    seg.add(b[at].second, 1);
                    at++;
                }
            }
        }
        y = seg.find_last([d = d](ll x){ return x < d; });
        d -= seg.get(0, y);
        ans[i] = to_string(A[x] * B[y])[d - 1];
    }
    cout << ans << endl;
}
accuracy: 1
time_ms: 330
memory_kb: 20776
final_rank: 7

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
using ll = long long;


template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b)a=b;};
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b)a=b;};

template<typename T> void drop(T x){cout<<x<<endl;exit(0);};

template<typename T, typename E>
struct SegmentTree{
  using F = function<T(T ,T)>;
  using G = function<T(T, E)>;
  using H = function<E(E, E)>;

  Int n, height;
  F f;
  G g;
  H h;
  T ti;
  E ei;
  vector<T> dat;
  vector<E> laz;

  SegmentTree(F f, G g, H h, T ti, E ei):
    f(f), g(g), h(h), ti(ti), ei(ei){}

  void init(Int n_){
    n = 1; height = 0;
    while(n < n_) n<<=1, height++;
    dat.assign(2*n, ti);
    laz.assign(2*n, ei);
  }

  void build(const vector<T> &v){
    Int n_ = v.size();
    init(n_);
    for(Int i=0;i<n_;i++) dat[n+i] = v[i];
    for(Int i=n-1;i;i--)
      dat[i] = f(dat[(i<<1)|0], dat[(i<<1)|1]);
  }

  inline T reflect(Int k){
    return laz[k] == ei? dat[k]:g(dat[k], laz[k]);
  }

  inline void eval(Int k){
    if(laz[k] == ei) return;
    laz[(k<<1)|0] = h(laz[(k<<1)|0], laz[k]);
    laz[(k<<1)|1] = h(laz[(k<<1)|1], laz[k]);
    dat[k] = reflect(k);
    laz[k] = ei;
  }

  inline void thrust(Int k){
    for(Int i=height;i;i--) eval(k>>i);
  }

  inline void recalc(Int k){
    while(k>>=1)
      dat[k] = f(reflect((k<<1)|0), reflect((k<<1)|1));
  }

  void update(Int a, Int b, E x){
    thrust(a += n);
    thrust(b += n-1);
    for(Int l=a, r=b+1;l<r;l>>=1, r>>=1){
      if(l&1) laz[l] = h(laz[l], x), l++;
      if(r&1) --r, laz[r] = h(laz[r], x);
    }
    recalc(a);
    recalc(b);
  }

  void set_val(Int a, T x){
    thrust(a += n);
    dat[a] = x; laz[a] = ei;
    recalc(a);
  }

  T query(Int a, Int b){
    thrust(a += n);
    thrust(b += n-1);
    T vl = ti, vr = ti;
    for(Int l=a, r=b+1;l<r;l>>=1, r>>=1){
      if(l&1) vl = f(vl, reflect(l++));
      if(r&1) vr = f(reflect(--r), vr);
    }
    return f(vl, vr);
  }

  template<typename C>
  Int find(Int st, C &check, T &acc, Int k, Int l, Int r){
    if(l + 1 == r){
      acc = f(acc, reflect(k));
      return check(acc)? k-n:-1;
    }
    eval(k);
    Int m = (l+r)>>1;
    if(m<=st) return find(st, check, acc, (k<<1)|1, m, r);

    if(st <= l && !check(f(acc, dat[k]))){
      acc = f(acc, dat[k]);
      return -1;
    }

    Int vl = find(st, check, acc, (k<<1)|0, l, m);
    if(~vl) return vl;
    return find(st, check, acc, (k<<1)|1, m, r);
  }

  template<typename C>
  Int find(Int st, C &check){
    T acc = ti;
    return find(st, check, acc, 1, 0, n);
  }
};


const Int MAX = 1e5+100;
Int dp[20][MAX];

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  Int n,m;
  cin>>n>>m;
  vector<Int> as(n),bs(m);
  for(Int i=0;i<n;i++) cin>>as[i];
  for(Int i=0;i<m;i++) cin>>bs[i];

  Int q;
  cin>>q;
  vector<Int> ds(q);
  for(Int i=0;i<q;i++) cin>>ds[i];

  string ans(q,'x');

  vector<Int> ss(bs);
  sort(ss.begin(),ss.end());

  for(Int i=0;i<n;i++){
    Int po=1;
    for(Int j=0;j<19;j++){
      auto pred=[&](Int x){return as[i]*x<po;};
      Int L=-1,R=m;
      while(L+1<R){
        Int M=(L+R)>>1;
        if(pred(ss[M])) L=M;
        else R=M;
      }
      dp[j][i]=R;
      if(j<18) po*=10;
    }

    dp[19][i]=m;
  }

  vector<Int> sm(n+1,0);
  for(Int i=0;i<n;i++){
    Int res=0;
    for(Int j=1;j<20;j++)
      res+=(dp[j][i]-dp[j-1][i])*j;
    sm[i+1]=sm[i]+res;
  }

  // sm[k] <= ds[i]
  vector< vector<Int> > I(n+2);
  for(Int i=0;i<q;i++){
    ds[i]--;
    Int k=upper_bound(sm.begin(),sm.end(),ds[i])-sm.begin()-1;
    //cout<<k<<endl;
    I[k].emplace_back(i);
  }

  using P = pair<Int, Int>;
  vector<P> vp,vq;
  for(Int i=0;i<n;i++) vp.emplace_back(as[i],i);
  for(Int i=0;i<m;i++) vq.emplace_back(bs[i],i);
  sort(vp.begin(),vp.end());
  sort(vq.rbegin(),vq.rend());

  auto f=[&](Int a,Int b){return a+b;};
  SegmentTree<Int, Int> seg(f,f,f,0,0);
  seg.build(vector<Int>(m+1,0));

  vector<Int> pos(20,0);
  for(Int i=0;i<n;i++){
    Int k=vp[i].second;

    Int po=1;
    for(Int j=0;j<19;j++){
      while((pos[j]<m)&&(vq[pos[j]].first*as[k]>=po)){
        Int q=vq[pos[j]].second;
        seg.set_val(q,j+1);
        pos[j]++;
      }
      if(j<18) po*=10;
    }

    for(Int j:I[k]){
      Int d=ds[j]-sm[k];
      // [0, p) <= d
      // [0, p] > d
      auto check=[&](Int s){return s>d;};
      Int p=seg.find(0,check);
      Int r=seg.query(0,p);
      assert(seg.query(0,p+0)<=d);
      assert(seg.query(0,p+1)> d);
      //cout<<d<<" "<<seg.query(0,p)<<" "<<seg.query(0,p+1)<<endl;
      d-=r;
      //cout<<j<<" "<<d<<":"<<to_string(as[k]*bs[p])<<endl;
      ans[j]=to_string(as[k]*bs[p])[d];
    }
  }

  cout<<ans<<endl;
  return 0;
}
accuracy: 1
time_ms: 450
memory_kb: 39736
final_rank: 9

code_snippet: #include<bits/stdc++.h>
using namespace std;
#ifndef ONLINE_JUDGE
#define dbg(x...) do { cout << "\033[32;1m " << #x << " -> "; err(x); } while (0)
void err() { cout << "\033[39;0m" << endl; }
template<template<typename...> class T, typename t, typename... A>
void err(T<t> a, A... x) { for (auto v: a) cout << v << ' '; err(x...); }
template<typename T, typename... A>
void err(T a, A... x) { cout << a << ' '; err(x...); }
#else
#define dbg(...)
#endif
typedef long long ll;
typedef pair<ll,ll> pi;
typedef vector<ll> vi;
template<class T> using vc=vector<T>;
template<class T> using vvc=vc<vc<T>>;
template<class T> void mkuni(vector<T>&v)
{
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
}
ll rand_int(ll l, ll r) //[l, r]
{
    static mt19937_64 gen(chrono::steady_clock::now().time_since_epoch().count());
    return uniform_int_distribution<ll>(l, r)(gen);
}
template<class T>
void print(T x,int suc=1)
{
    cout<<x;
    if(suc==1) cout<<'\n';
    else cout<<' ';
}
template<class T>
void print(const vector<T>&v,int suc=1)
{
    for(int i=0;i<v.size();i++)
    print(v[i],i==(int)(v.size())-1?suc:2);
}
struct Bit{
	vc<ll> t;
	int sz;
	Bit(int n){
		sz=n+2;
		t=vc<ll>(sz);
	}
	void add(int x,int val)
	{
		x++;
		while(x<sz)
		{
			t[x]+=val;
			x+=x&-x;
		}
	}
	ll query(int x)
	{
		x++;
		ll ret=0;
		while(x)
		{
			ret+=t[x];
			x-=x&-x;
		}
		return ret;
	}
};
int getl(int x)
{
	ll v=10;
	int cc=0;
	while(x/v!=0)
	{
		cc++;
		v*=10;
	}
	return cc;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	int n,m;
	cin>>n>>m;
	vc<pi> a(n),b(m);
	vc<pi> mb(m);
	vi sb(m);
	vi cnt(m);
	auto modify=[&](ll x){
		while(x<1000000000) x*=10;
		return x;
	};
	for(int i=0;i<n;i++)
	{
		cin>>a[i].first;
		a[i].second=i;
	}
	for(int i=0;i<m;i++)
	{
		cin>>b[i].first;
		sb[i]=b[i].first;
		mb[i]=make_pair(modify(b[i].first),i);
		b[i].second=i;
		cnt[i]=getl(b[i].first);
	}
	sort(mb.begin(),mb.end());
	ll sum=0;
	Bit T(m);
	for(int i=0;i<m;i++)
	{
		sum+=cnt[i]+1;
		T.add(i,cnt[i]+1);
	}
	auto check=[&](ll x,ll y){
		const __int128 tar=1e19;
		return (__int128)x*y>=tar;
	};
	auto getc=[&](ll x){
		int L=0,R=m-1,ret=-1;
		x=modify(x);
		while(L<=R)
		{
			int mid=L+R>>1;
			ll y=mb[mid].first;
			if(!check(x,y))
			{
				ret=mid;
				L=mid+1;
			}
			else R=mid-1;
		}
		return m-1-ret;
	};
	vc<ll> pre(n);
	for(int i=0;i<n;i++)
	{
		ll cc=getl(a[i].first);
		pre[i]=sum+cc*m+getc(a[i].first);
		if(i) pre[i]+=pre[i-1];
	}
	//dbg(pre);
	int q;
	cin>>q;
	using tp=tuple<int,ll,int>;
	vc<tp> query;
	vi ans(q);
	for(int i=0;i<q;i++)
	{
		ll d;
		cin>>d;
		//dbg(i,d);
		if(d>pre[n-1]) ans[i]=-1;
		else{
			int line=lower_bound(pre.begin(),pre.end(),d)-pre.begin();
			ll rem=d-(line?pre[line-1]:0);
			//dbg(line,rem,i);
			query.emplace_back(line,rem,i);
		}
	}
	sort(query.begin(),query.end(),[&](tp x,tp y){
		return modify(a[get<0>(x)].first)<modify(a[get<0>(y)].first);
	});
	int pp=m-1;
	for(auto u:query)
	{
		int line,id;ll rem;
		tie(line,rem,id)=u;
		while(pp>=0&&check(mb[pp].first,modify(a[line].first)))
		{
			//dbg(mb[pp].first,a[line].first);
			T.add(mb[pp].second,1);
			pp--;
		}
		int L=0,R=m-1,ret=-1;
		int ca=getl(a[line].first);
		while(L<=R)
		{
			int mid=L+R>>1;
			if(T.query(mid)+(ll)(mid+1)*ca>=rem)
			{
				R=mid-1;
				ret=mid;
			}
			else L=mid+1;
		}
		assert(ret!=-1);
		ll tn=a[line].first*sb[ret];
		int cc=T.query(ret)+(ret+1)*ca-rem;
		//dbg(T.query(ret)+(ret+1)*ca,line,tn,cc,id);
		while(cc)
		{
			tn/=10;
			cc--;
		}
		ans[id]=tn%10;
	}
	for(int i=0;i<q;i++)
	{
		if(ans[i]==-1) cout<<'x';
		else cout<<ans[i];
	}
	cout<<'\n';
}
accuracy: 1
time_ms: 240
memory_kb: 27620
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ll = long long;
using ld = long double;

template <typename T>
class fenwick_tree {
public:
    fenwick_tree(int n_) : n(n_), dat(n_) {}

    void add(int i, T val) {
        for(; i < n; i |= i + 1) {
            dat[i] += val;
        }
    }

    ll sum(int i) const {
        T res = 0;
        for(; i >= 0; i = (i & (i + 1)) - 1) {
            res += dat[i];
        }
        return res;
    }
    T sum(int l, int r) const {
        return sum(r - 1) - sum(l - 1);
    }

private:
    const int n;
    vector<T> dat;
};

pair<ld, ll> decomp(ld val) {
    int cnt = 0;
    while(val >= 10.0) {
        cnt += 1;
        val /= 10;
    }
    return make_pair(val, cnt);
}

int main() {
    ios_base::sync_with_stdio(false); cin.tie(0);

    int n, m; cin >> n >> m;
    vector<ll> a(n), b(m);
    for(auto& x : a) cin >> x;
    for(auto& x : b) cin >> x;

    fenwick_tree<ll> sum_b(m + 1);
    vector<pair<ld, int>> bs(m);
    for(int i = 0; i < m; ++i) {
        auto p = decomp(b[i]);
        sum_b.add(i, p.second + 1);
        bs[i] = make_pair(p.first, i);
    }
    sort(bs.begin(), bs.end());

    vector<ll> sum(n + 1);
    vector<pair<ld, ll>> aval(n);
    for(int i = 0; i < n; ++i) {
        auto p = decomp(a[i]);
        aval[i] = p;
        sum[i + 1] = sum[i] + p.second * m + sum_b.sum(0, m);
        sum[i + 1] += bs.end() - lower_bound(bs.begin(), bs.end(), make_pair(10.0L / p.first, -1));
    }
    reverse(bs.begin(), bs.end());

    int q; cin >> q;
    vector<ll> d(q), aidx(q);
    string ans(q, ' ');
    for(int i = 0; i < q; ++i) {
        cin >> d[i];
        int lb = 0, ub = n + 1;
        while(ub - lb > 1) {
            const int mid = (ub + lb) / 2;
            (sum[mid] >= d[i] ? ub : lb) = mid;
        }
        if(ub == n + 1) {
            ans[i] = 'x';
        } else {
            aidx[i] = lb;
        }
    }
    vector<int> qord(q);
    iota(qord.begin(), qord.end(), 0);
    sort(qord.begin(), qord.end(), [&] (int i, int j) { return aval[aidx[i]].first < aval[aidx[j]].first; });

    int b_it = 0;
    for(auto const qi : qord) {
        if(ans[qi] == 'x') continue;
        const int ai = aidx[qi];
        while(b_it < m && bs[b_it].first * aval[ai].first >= 10.0L) {
            sum_b.add(bs[b_it++].second, 1);
        }
        ll lb = 0, ub = m;
        while(ub - lb > 1) {
            const int mid = (lb + ub) / 2;
            const ll s = sum[ai] + sum_b.sum(0, mid) + aval[ai].second * mid;
            (s >= d[qi] ? ub : lb) = mid;
        }
        const ll offset = d[qi] - (sum[ai] + sum_b.sum(0, lb) + aval[ai].second * lb);
        ans[qi] = to_string(a[ai] * b[lb])[offset - 1];
    }

    cout << ans << endl;
}
accuracy: 1
time_ms: 260
memory_kb: 18484
final_rank: 3

code_snippet: #include <iostream>
#include <vector>
#include <array>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <tuple>
#include <bitset>
#include <memory>
#include <cmath>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <numeric>
#include <climits>
#include <cfloat>
#include <fstream>
constexpr long long int power(const long long int base, const int exp) {
	switch (exp) {
	case 0: return 1;
	case 1: return base;
	default: return power(base * base, exp / 2) * power(base, exp % 2);
	}
}
char get_digit(long long int number, const long long int digit) {
	int count = 0;
	for (auto n = number; n > 0; n /= 10) ++count;
	for (int i = count - digit; i > 0; --i) {
		number /= 10;
	}
	return number % 10 + '0';
}
int main() {
	std::cin.tie(0); std::cin.sync_with_stdio(false);
	constexpr std::array<long long int, 19> digits{ power(10, 0), power(10, 1), power(10, 2), power(10, 3), power(10, 4), power(10, 5), power(10, 6), power(10, 7), power(10, 8), power(10, 9), power(10, 10), power(10, 11), power(10, 12), power(10, 13), power(10, 14), power(10, 15), power(10, 16), power(10, 17), power(10, 18) };
	int n, m; std::cin >> n >> m;
	std::vector<int> row(n), column(m);
	for (auto& r : row) std::cin >> r;
	for (auto& c : column) std::cin >> c;
	std::vector<std::vector<int>> sub_array(m);
	for (auto i = 0; i < m; ++i) {
		for (auto position = i; position < sub_array.size(); position += ~position & (position + 1)) {
			sub_array[position].push_back(column[i]);
		}
		std::sort(sub_array[i].begin(), sub_array[i].end());
	}
	auto column_sorted = column;
	std::sort(column_sorted.begin(), column_sorted.end());
	std::vector<long long int> digit_by_row; digit_by_row.reserve(n);
	for (const auto r : row) {
		int digit_count = 0;
		int count = 0;
		for (auto digit = 1; digit <= 19; ++digit) {
			auto upper = std::upper_bound(std::next(column_sorted.begin(), count), column_sorted.end(), (digits[digit - 1] - 1) / r);
			if (upper == column_sorted.end()) break;
			digit_count += std::distance(upper, column_sorted.end());
			count = std::distance(column_sorted.begin(), upper);
		}
		digit_by_row.push_back(digit_count);
	}
	for (auto i = 1; i < n; ++i) digit_by_row[i] += digit_by_row[i - 1];
	int max_bit = 1;
	for (auto i = m; i > 1; i >>= 1) max_bit <<= 1;
	int q; std::cin >> q;
	//std::string result; result.reserve(q);
	for (auto _i = 0; _i < q; ++_i) {
		long long int d; std::cin >> d;
		if (d > digit_by_row.back()) {
			//result.push_back('x');
			std::cout << 'x';
			continue;
		}
		auto row_count = std::distance(digit_by_row.begin(), std::lower_bound(digit_by_row.begin(), digit_by_row.end(), d));
		if (row_count != 0) d -= digit_by_row[row_count - 1];
		const long long int r = row[row_count];
		int column_pos = 0;
		for (int pos = max_bit - 1; pos >= 0; pos = ((pos + 1) >> 1) - 1) if (column_pos + pos < sub_array.size()) {
			int digit_count = 0;
			int count = 0;
			for (auto digit = 1; digit <= 19; ++digit) {
				auto upper = std::upper_bound(std::next(sub_array[column_pos + pos].begin(), count), sub_array[column_pos + pos].end(), (digits[digit - 1] - 1) / r);
				if (upper == sub_array[column_pos + pos].end()) break;
				digit_count += std::distance(upper, sub_array[column_pos + pos].end());
				if (digit_count >= d) break;
				count = std::distance(sub_array[column_pos + pos].begin(), upper);
			}
			if (digit_count < d) {
				column_pos += pos + 1;
				d -= digit_count;
			}
		}
		std::cout << get_digit(r * column[column_pos], d);
		//result.push_back(get_digit(r * column[column_pos], d));
	}
	//std::cout << result << '\n';
	std::cout << '\n';
}
accuracy: 1
time_ms: 1650
memory_kb: 12916
final_rank: 12

code_snippet: #include <iostream>
#include <vector>
#include <array>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <tuple>
#include <bitset>
#include <memory>
#include <cmath>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <numeric>
#include <climits>
#include <cfloat>
#include <fstream>
constexpr long long int power(const long long int base, const int exp) {
	switch (exp) {
	case 0: return 1;
	case 1: return base;
	default: return power(base * base, exp / 2) * power(base, exp % 2);
	}
}
char get_digit(long long int number, const long long int digit) {
	int count = 0;
	for (auto n = number; n > 0; n /= 10) ++count;
	for (int i = count - digit; i > 0; --i) {
		number /= 10;
	}
	return number % 10 + '0';
}
int main() {
	std::cin.tie(0); std::cin.sync_with_stdio(false);
	constexpr std::array<long long int, 19> digits{ power(10, 0), power(10, 1), power(10, 2), power(10, 3), power(10, 4), power(10, 5), power(10, 6), power(10, 7), power(10, 8), power(10, 9), power(10, 10), power(10, 11), power(10, 12), power(10, 13), power(10, 14), power(10, 15), power(10, 16), power(10, 17), power(10, 18) };
	int n, m; std::cin >> n >> m;
	std::vector<int> row(n), column(m);
	for (auto& r : row) std::cin >> r;
	for (auto& c : column) std::cin >> c;
	std::vector<std::vector<int>> sub_array(m);
	for (auto i = 0; i < m; ++i) {
		for (auto position = i; position < sub_array.size(); position += ~position & (position + 1)) {
			sub_array[position].push_back(column[i]);
		}
		std::sort(sub_array[i].begin(), sub_array[i].end());
	}
	auto column_sorted = column;
	std::sort(column_sorted.begin(), column_sorted.end());
	std::vector<long long int> digit_by_row; digit_by_row.reserve(n);
	for (const auto r : row) {
		int digit_count = 0;
		int count = 0;
		for (auto digit = 1; digit <= 18; ++digit) {
			auto upper = std::upper_bound(std::next(column_sorted.begin(), count), column_sorted.end(), (digits[digit - 1] - 1) / r);
			if (upper == column_sorted.end()) break;
			digit_count += std::distance(upper, column_sorted.end());
			count = std::distance(column_sorted.begin(), upper);
		}
		digit_by_row.push_back(digit_count);
	}
	for (auto i = 1; i < n; ++i) digit_by_row[i] += digit_by_row[i - 1];
	int max_bit = 1;
	for (auto i = m; i > 1; i >>= 1) max_bit <<= 1;
	int q; std::cin >> q;
	//std::string result; result.reserve(q);
	for (auto _i = 0; _i < q; ++_i) {
		long long int d; std::cin >> d;
		if (d > digit_by_row.back()) {
			//result.push_back('x');
			std::cout << 'x';
			continue;
		}
		auto row_count = std::distance(digit_by_row.begin(), std::lower_bound(digit_by_row.begin(), digit_by_row.end(), d));
		if (row_count != 0) d -= digit_by_row[row_count - 1];
		const long long int r = row[row_count];
		int column_pos = 0;
		for (int pos = max_bit - 1; pos >= 0; pos = ((pos + 1) >> 1) - 1) if (column_pos + pos < sub_array.size()) {
			int digit_count = 0;
			int count = 0;
			for (auto digit = 1; digit <= 18; ++digit) {
				auto upper = std::upper_bound(std::next(sub_array[column_pos + pos].begin(), count), sub_array[column_pos + pos].end(), (digits[digit - 1] - 1) / r);
				if (upper == sub_array[column_pos + pos].end()) break;
				digit_count += std::distance(upper, sub_array[column_pos + pos].end());
				if (digit_count >= d) break;
				count = std::distance(sub_array[column_pos + pos].begin(), upper);
			}
			if (digit_count < d) {
				column_pos += pos + 1;
				d -= digit_count;
			}
		}
		std::cout << get_digit(r * column[column_pos], d);
		//result.push_back(get_digit(r * column[column_pos], d));
	}
	//std::cout << result << '\n';
	std::cout << '\n';
}
accuracy: 0.9264705882352942
time_ms: 1650
memory_kb: 12916
final_rank: 17

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 100005

struct Info{

	bool operator<(const struct Info &arg) const{

		return base < arg.base;
	}

	int index;
	ll base,digit;
};

struct Query{

	bool operator<(const struct Query &arg) const{

		return loc < arg.loc;
	}

	ll loc;
	int index;
};

int H,W;
ll ans[3*SIZE];
ll POW[18];
ll BIT[SIZE];
ll num_row[SIZE],num_col[SIZE];
ll sum_digit[SIZE];
ll COL_SUM_DIGIT;
Info ROW[SIZE],COL[SIZE];
vector<Query> V_Query,QUERY[SIZE];
vector<Info> V_ROW,V_COL;


//仮数部の桁が増えるかチェックする関数→桁が増えるならtrueを返す
bool increase_digit(Info A,Info B){

	ll tmp = A.base*B.base;

	return tmp >= POW[17];
}

void add(int loc,ll value){

	BIT[loc] += value;

	loc += loc & -loc; //最後の1ビットを足した場所が次の★更新★場所

	while(loc <= W){
		BIT[loc] += value;
		loc += loc & -loc;
	}
}

ll getSum(int loc){

	ll sum = BIT[loc];

	loc -= loc & -loc; //最後の1ビットを引いた場所が次の★加算★場所

	while(loc > 0){
		sum += BIT[loc];
		loc -= loc & -loc;
	}
	return sum;
}

ll calc(int left,int right){ //left～rightの区間の総和を、sum(1～right)-sum(1～left-1)で求める
	return getSum(right)-getSum(left-1);
}

int main(){

	POW[0] = 1;
	for(int i = 1; i < 18; i++){

		POW[i] = POW[i-1]*10;
	}

	scanf("%d %d",&H,&W);

	ll tmp;
	ll num_digit;

	for(int i = 1; i <= H; i++){

		scanf("%lld",&tmp);
		num_row[i] = tmp;

		for(num_digit = 1; ;num_digit++){

			if(POW[num_digit] > tmp)break;
		}

		if(num_digit == 10){ //10億

			ROW[i].base = tmp/10;

		}else{

			ROW[i].base = tmp*POW[9-num_digit];
		}

		ROW[i].digit = num_digit-1;
		ROW[i].index = i;

		V_ROW.push_back(ROW[i]);
	}

	sort(V_ROW.begin(),V_ROW.end());

	COL_SUM_DIGIT = 0; //列の各数の桁の総和

	for(int i = 1; i <= W; i++){

		scanf("%lld",&tmp);
		num_col[i] = tmp;

		for(num_digit = 1; ;num_digit++){

			if(POW[num_digit] > tmp)break;
		}

		if(num_digit == 10){ //10億

			COL[i].base = tmp/10;

		}else{

			COL[i].base = tmp*POW[9-num_digit];
		}

		COL[i].digit = num_digit-1;
		COL[i].index = i;

		COL_SUM_DIGIT += COL[i].digit;

		V_COL.push_back(COL[i]);
	}

	sort(V_COL.begin(),V_COL.end());

	//行ごとの、桁の数を計算する

	sum_digit[0] = 0;

	int L,R,mid;
	ll plus_2,plus_1;

	for(int row = 1; row <= H; row++){

		L = 0,R = W-1,mid = (L+R)/2; //★V_COLに合わせるので0オリジン★
		int left_col = W;

		while(L <= R){

			if(increase_digit(ROW[row],V_COL[mid])){

				left_col = mid;
				R = mid-1; //より左へ

			}else{

				L = mid+1;
			}
			mid = (L+R)/2;
		}

		plus_2 = W-left_col;
		plus_1 = W-plus_2;

		sum_digit[row] = ROW[row].digit*W+COL_SUM_DIGIT+2*plus_2+plus_1;

		if(row == 0)continue;

		sum_digit[row] += sum_digit[row-1];
	}

	int num_query;
	scanf("%d",&num_query);

	for(int i = 0; i < num_query; i++){

		Query query;
		scanf("%lld",&query.loc);
		query.index = i;

		V_Query.push_back(query);
	}

	sort(V_Query.begin(),V_Query.end());

	L = 1;
	int loc_row;

	for(int i = 0; i < num_query; i++){

		if(V_Query[i].loc > sum_digit[H]){

			ans[V_Query[i].index] = -1;
			continue;
		}

		R = H,mid = (L+R)/2;

		//どの行の、どの相対位置かを求める

		while(L <= R){

			if(sum_digit[mid] >= V_Query[i].loc){

				loc_row = mid;
				R = mid-1;

			}else{

				L = mid+1;
			}
			mid = (L+R)/2;
		}

		Query query;
		query.loc = V_Query[i].loc-sum_digit[loc_row-1]; //★1オリジンなので注意★
		query.index = V_Query[i].index;

		QUERY[loc_row].push_back(query);
	}

	for(int i = 0; i <= W; i++)BIT[i] = 0;

	for(int i = 1; i <= W; i++){

		add(i,COL[i].digit+1);
	}


	int pre_left_col = -1;

	stack<ll> S;

	for(int i = 0; i < H; i++){ //行を仮数の昇順に処理

		//仮数の掛け算で繰り上がりする左端を求める

		L = 0,R = W-1,mid = (L+R)/2; //★V_COLに合わせるので0オリジン★
		int left_col = -1;
		int row = V_ROW[i].index;

		while(L <= R){

			if(increase_digit(ROW[row],V_COL[mid])){

				left_col = mid;
				R = mid-1; //より左へ

			}else{

				L = mid+1;
			}
			mid = (L+R)/2;
		}

		if(pre_left_col == -1){

			if(left_col != -1){

				for(int col = left_col; col <= W-1; col++){

					add(V_COL[col].index,1); //本来の位置に加算
				}
			}

		}else{

			if(left_col != -1){

				for(int col = left_col; col < pre_left_col; col++){

					add(V_COL[col].index,1); //本来の位置に加算
				}
			}
		}

		pre_left_col = left_col;

		if(QUERY[row].size() == 0)continue;

		for(int k = 0; k < QUERY[row].size(); k++){

			int l = 1,r = W;
			mid = (l+r)/2;
			int loc_col = -1;

			while(l <= r){

				tmp = calc(1,mid)+ROW[row].digit*mid;

				if(tmp >= QUERY[row][k].loc){

					loc_col = mid;
					r = mid-1;

				}else{

					l = mid+1;
				}
				mid = (l+r)/2;
			}

			ll calc_digit = QUERY[row][k].loc;

			if(loc_col > 1){

				calc_digit -= (calc(1,loc_col-1)+ROW[row].digit*(loc_col-1));
			}

			//numberのcalc_digit桁目
			ll number = num_row[row]*num_col[loc_col];

			while(!S.empty())S.pop();

			while(true){

				S.push(number%10);
				number /= 10;

				if(number == 0)break;
			}

			for(int count = 0; count < calc_digit; count++){

				ans[QUERY[row][k].index] = S.top();
				S.pop();
			}
		}
	}

	for(int i = 0; i < num_query; i++){

		if(ans[i] == -1){

			printf("x");
		}else{

			printf("%lld",ans[i]);
		}
	}

	printf("\n");

	return 0;
}
accuracy: 1
time_ms: 220
memory_kb: 31424
final_rank: 6

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
using ll = long long;


template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b)a=b;};
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b)a=b;};

template<typename T> void drop(T x){cout<<x<<endl;exit(0);};

template<typename T, typename E>
struct SegmentTree{
  using F = function<T(T ,T)>;
  using G = function<T(T, E)>;
  using H = function<E(E, E)>;

  Int n, height;
  F f;
  G g;
  H h;
  T ti;
  E ei;
  vector<T> dat;
  vector<E> laz;

  SegmentTree(F f, G g, H h, T ti, E ei):
    f(f), g(g), h(h), ti(ti), ei(ei){}

  void init(Int n_){
    n = 1; height = 0;
    while(n < n_) n<<=1, height++;
    dat.assign(2*n, ti);
    laz.assign(2*n, ei);
  }

  void build(const vector<T> &v){
    Int n_ = v.size();
    init(n_);
    for(Int i=0;i<n_;i++) dat[n+i] = v[i];
    for(Int i=n-1;i;i--)
      dat[i] = f(dat[(i<<1)|0], dat[(i<<1)|1]);
  }

  inline T reflect(Int k){
    return laz[k] == ei? dat[k]:g(dat[k], laz[k]);
  }

  inline void eval(Int k){
    if(laz[k] == ei) return;
    laz[(k<<1)|0] = h(laz[(k<<1)|0], laz[k]);
    laz[(k<<1)|1] = h(laz[(k<<1)|1], laz[k]);
    dat[k] = reflect(k);
    laz[k] = ei;
  }

  inline void thrust(Int k){
    for(Int i=height;i;i--) eval(k>>i);
  }

  inline void recalc(Int k){
    while(k>>=1)
      dat[k] = f(reflect((k<<1)|0), reflect((k<<1)|1));
  }

  void update(Int a, Int b, E x){
    thrust(a += n);
    thrust(b += n-1);
    for(Int l=a, r=b+1;l<r;l>>=1, r>>=1){
      if(l&1) laz[l] = h(laz[l], x), l++;
      if(r&1) --r, laz[r] = h(laz[r], x);
    }
    recalc(a);
    recalc(b);
  }

  void set_val(Int a, T x){
    thrust(a += n);
    dat[a] = x; laz[a] = ei;
    recalc(a);
  }

  T query(Int a, Int b){
    thrust(a += n);
    thrust(b += n-1);
    T vl = ti, vr = ti;
    for(Int l=a, r=b+1;l<r;l>>=1, r>>=1){
      if(l&1) vl = f(vl, reflect(l++));
      if(r&1) vr = f(reflect(--r), vr);
    }
    return f(vl, vr);
  }

  template<typename C>
  Int find(Int st, C &check, T &acc, Int k, Int l, Int r){
    if(l + 1 == r){
      acc = f(acc, reflect(k));
      return check(acc)? k-n:-1;
    }
    eval(k);
    Int m = (l+r)>>1;
    if(m<=st) return find(st, check, acc, (k<<1)|1, m, r);

    if(st <= l && !check(f(acc, dat[k]))){
      acc = f(acc, dat[k]);
      return -1;
    }

    Int vl = find(st, check, acc, (k<<1)|0, l, m);
    if(~vl) return vl;
    return find(st, check, acc, (k<<1)|1, m, r);
  }

  template<typename C>
  Int find(Int st, C &check){
    T acc = ti;
    return find(st, check, acc, 1, 0, n);
  }
};


const Int MAX = 1e5+100;
Int dp[20][MAX];

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  Int n,m;
  cin>>n>>m;
  vector<Int> as(n),bs(m);
  for(Int i=0;i<n;i++) cin>>as[i];
  for(Int i=0;i<m;i++) cin>>bs[i];

  Int q;
  cin>>q;
  vector<Int> ds(q);
  for(Int i=0;i<q;i++) cin>>ds[i];

  string ans(q,'x');

  vector<Int> ss(bs);
  sort(ss.begin(),ss.end());

  for(Int i=0;i<n;i++){
    Int po=1;
    for(Int j=0;j<19;j++){
      auto pred=[&](Int x){return as[i]*x<po;};
      Int L=-1,R=m;
      while(L+1<R){
        Int M=(L+R)>>1;
        if(pred(ss[M])) L=M;
        else R=M;
      }
      dp[j][i]=R;
      if(j<18) po*=10;
    }

    dp[19][i]=m;
  }

  vector<Int> sm(n+1,0);
  for(Int i=0;i<n;i++){
    Int res=0;
    for(Int j=1;j<20;j++)
      res+=(dp[j][i]-dp[j-1][i])*j;
    sm[i+1]=sm[i]+res;
  }

  // sm[k] <= ds[i]
  vector< vector<Int> > I(n+2);
  for(Int i=0;i<q;i++){
    ds[i]--;
    Int k=upper_bound(sm.begin(),sm.end(),ds[i])-sm.begin()-1;
    //cout<<k<<endl;
    I[k].emplace_back(i);
  }

  using P = pair<Int, Int>;
  vector<P> vp,vq;
  for(Int i=0;i<n;i++) vp.emplace_back(as[i],i);
  for(Int i=0;i<m;i++) vq.emplace_back(bs[i],i);
  sort(vp.begin(),vp.end());
  sort(vq.rbegin(),vq.rend());

  auto f=[&](Int a,Int b){return a+b;};
  SegmentTree<Int, Int> seg(f,f,f,0,0);
  seg.build(vector<Int>(m+1,0));

  vector<Int> pos(20,0);
  for(Int i=0;i<n;i++){
    Int k=vp[i].second;

    Int po=1;
    for(Int j=0;j<19;j++){
      while((pos[j]<m)&&(vq[pos[j]].first*as[k]>=po)){
        Int q=vq[pos[j]].second;
        seg.set_val(q,j+1);
        pos[j]++;
      }
      if(j<18) po*=10;
    }

    for(Int j:I[k]){
      Int d=ds[j]-sm[k];
      // [0, p) <= d
      // [0, p] > d
      auto check=[&](Int s){return s>d;};
      Int p=seg.find(0,check);
      Int r=seg.query(0,p);
      assert(seg.query(0,p+0)<=d);
      assert(seg.query(0,p+1)> d);
      //cout<<d<<" "<<seg.query(0,p)<<" "<<seg.query(0,p+1)<<endl;
      d-=r;
      //cout<<j<<" "<<d<<":"<<to_string(as[k]*bs[p])<<endl;
      ans[j]=to_string(as[k]*bs[p])[d];
    }
  }

  cout<<ans<<endl;
  return 0;
}
accuracy: 1
time_ms: 520
memory_kb: 39556
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
//const int MOD=1e9+7;
//const int MOD=998244353;
const int INF=1e9;
const long long LINF=1e18;
#define int long long
//template

template <typename T>
void fin(T a){
  cout<<a<<endl;
  exit(0);
}
typedef pair<int,int> P;
typedef pair<P,P> PP;
template <typename T>
struct SegmentTree{
  using F = function<T(T,T)>;
  int n;  //セグ木の幅
  F f;  //モノイドの作用
  T ti;  //初期値
  vector<T> dat;  //セグ木で使う配列 一番上に使われるのがdat[1] 一番下の段の左端がdat[n]
  SegmentTree(){};
  SegmentTree(F f,T ti):f(f),ti(ti){}  //fがモノイドとしての作用、tiが初期値

  void init(int n_){  //ただの初期化
    n=1;
    while(n<n_) n<<=1;  //nが実際にとる２べきの幅
    dat.assign(n<<1,ti);  //dat配列は幅の２倍あってその全てにtiを代入
  }

  void build(const vector<T> &v){  //vector vに合わせた初期化
    int n_=v.size();
    init(n_);
    for(int i=0;i<n_;i++) dat[n+i]=v[i];  //v[i]を一番子の所に代入
    for(int i=n-1;i;i--)
      dat[i]=f(dat[(i<<1)|0],dat[(i<<1)|1]);  //iの子供は2*i、2*i+1
  }

  void set_val(int k,T x){  //（0-indexedで）kにxを代入
    dat[k+=n]=x;
    while(k>>=1)  //kがどんどん自分の親になっていく、0になったらおしまい
      dat[k]=f(dat[(k<<1)|0],dat[(k<<1)|1]);
  }

  void add_val(int k,T x){
    int a=dat[k+n];
    set_val(k,a+x);
  }

  T query(int a,int b){  //[a,b)の範囲のモノイドの作用を返す
    T vl=ti,vr=ti;
    for(int l=a+n,r=b+n;l<r;l>>=1,r>>=1) {
      if(l&1) vl=f(vl,dat[l++]);  //左端を使いたくなるのはブロックが奇数の時
      if(r&1) vr=f(dat[--r],vr);  //右端〃偶数の時（開区間なのでr:奇数で反応）
    }
    return f(vl,vr);
  }

  template<typename C>
  int find(int st,C &check,T &acc,int k,int l,int r){  //dat[k]:[l,r)の間にいるenを返す
    //下のfind用なので先にそっち読むべき
    //accはst~lとかで確定している値
    if(l+1==r){  //答えがちゃんと存在するならこのlが答え
      acc=f(acc,dat[k]);
      return check(acc)?k-n:-1; //入るならk-n(==l)を、入らないなら-1を返す
    }
    int m=(l+r)>>1;  //にぶたんのそれ
    if(m<=st) return find(st,check,acc,(k<<1)|1,m,r);  //mがstより後ろなら明らかにl=m;
    if(st<=l&&!check(f(acc,dat[k]))){  //今見てるk全部でもダメ(mだと足りないのでl=mにする）
      acc=f(acc,dat[k]);  //kは全部accに加えた上で-1を返す
      return -1;
    }
    int vl=find(st,check,acc,(k<<1)|0,l,m);  //まず[l,m)の中にenがいるか探す
    if(~vl) return vl;  //いたならそれを返す(if(~vl)は-1以外にのみ反応する)
    return find(st,check,acc,(k<<1)|1,m,r);  //いなかったら[m,r)の中にenがいるのでそれを返す
    //acc=f(acc,dat[k]);がここで効いてる
  }

  template<typename C>
  int find(int st,C &check){
    //check(f(dat[st]~dat[en-1]))=false,check(f(dat[st]~dat[en]))＝trueとなるenを返す
    T acc=ti;
    return find(st,check,acc,1,0,n);
  }
};
int pw(int n,int k){
  //if(k<0)return pw(n,k+MOD-1);
  int res=1;
  while(k){
    if(k&1)res*=n;//res%=MOD;
    n*=n;//n%=MOD;
    k>>=1;
  }
  return res;
}
char st(int a,int b){
  string s;
  while(a){
    s+=('0'+a%10);a/=10;
  }
  reverse(s.begin(),s.end());
  return s[b-1];
}
//main
signed main(){
  int N,M,Q;cin>>N>>M;
  vector<int> a(N),b(M),ae(N),as(N),be(M),bs(M);
  int EI=1e8;
  for(int i=0;i<N;i++){
    cin>>a[i];
    int j=1;while(a[i]>=pw(10,j))j++;j--;
    ae[i]=a[i]*EI/pw(10,j);as[i]=j;
  } //make as&ae
  for(int i=0;i<M;i++){
    cin>>b[i];
    int j=1;while(b[i]>=pw(10,j))j++;j--;
    be[i]=b[i]*EI/pw(10,j);bs[i]=j;
  } //make bs&be

  int sum_bs=0;for(int i=0;i<M;i++)sum_bs+=bs[i];

  cin>>Q;  vector<int> d(Q);
  for(int i=0;i<Q;i++)cin>>d[i];

  //for(int i=0;i<N;i++)cout<<as[i]<<" ";cout<<endl;
  //for(int i=0;i<M;i++)cout<<bs[i]<<" ";cout<<endl;
  //cout<<sum_bs<<endl;

  vector<int> afin(N+1,0);//afin[i+1]:a[i]が終わった時の合計文字数
  vector<P> sorted_be(M);
  for(int i=0;i<M;i++)sorted_be[i]=P(be[i],i);
  sort(sorted_be.begin(),sorted_be.end());
  for(int i=0;i<N;i++){
    int l=-1,r=M;//a[i]*sorted_be[l]がギリギリ1e17を超えないライン
    while(r-l>1){
      int m=(l+r)/2;
      int X=sorted_be[m].first;
      if(ae[i]*X<1e17)l=m;
      else r=m;
    }
    afin[i+1]=afin[i]+sum_bs+(as[i]+1)*M+M-r;//l+1が繰り上がりの数
  }
  std::vector<char> ans(Q);

  set<PP> s;//sに入るのは(i番目の答えが入る行に書かれた数字、行の名前、その行で必要な個数、i)
  for(int i=0;i<Q;i++){
    int D=d[i];if(afin[N]<D){ans[i]='x';continue;}
    int l=-1,r=N;//Dがいるのはr行目  lはギリギリafin[l+1]<Dを満たす
    while(r-l>1){
      int m=(l+r)/2;
      if(afin[m+1]<D)l=m;
      else r=m;
    }
    s.insert(PP(P(ae[r],r),P(D-afin[l+1],i)));
    //cout<<a[r]<<" "<<r<<" "<<D-afin[l+1]<<" "<<i<<endl;
  }
  auto f=[](int a,int b){return a+b;};
  SegmentTree<int> seg(f,0);
  seg.build(bs);
  int now=0;
  reverse(sorted_be.begin(),sorted_be.end());
  for(auto p:s){
    int A=p.first.first,columm=p.first.second,row=p.second.first;
    while(now<M&&sorted_be[now].first*A>=1e17){
      seg.add_val(sorted_be[now].second,1);
      now++;
    }
    int l=-1,r=M;//seg.query(0,l)っぽいのがギリギリrowより小さいやつ
    while(r-l>1){
      int m=(l+r)/2;
      if(seg.query(0,m)+(as[columm]+1)*m<row)l=m;
      else r=m;
    }
    int res=row-(seg.query(0,l)+(as[columm]+1)*l);
    int R=a[columm]*b[l];
    //cout<<"ERT"<<p.second.second<<" "<<r<<" "<<res<<" "<<R<<" "<<seg.query(0,l)<<endl;
    ans[p.second.second]=st(R,res);
  }
  for(int i=0;i<Q;i++)cout<<ans[i];cout<<endl;
}
accuracy: 1
time_ms: 710
memory_kb: 35572
final_rank: 11

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> l_l;
ll N, M;
ll a[100050], b[100050];
ll beki[20];
ll Q;
vector<l_l> d;
ll SqrtM = 1000;
ll WM = (100000 + SqrtM - 1) / SqrtM;
char ans[300050];
ll num[100050][341];
ll number[340];
ll zero[341];

ll gcd(ll a, ll b) {
    if(a < b) swap(a, b);
    if(a % b == 0) return b;
    return gcd(b, a % b);
}

struct rational {
  ll p, q;
  void normalize() { // keep q positive
    if (q < 0) p *= -1, q *= -1;
    ll d = gcd(p < 0 ? -p : p, q);
    if (d == 0) p = 0,  q = 1;
    else        p /= d, q /= d;
  }
  rational(ll p, ll q = 1) : p(p), q(q) {
    normalize();
  }
  rational() {
      p = 0;
      q = 1;
  }
  rational &operator += (const rational &a) {
    p = a.q * p + a.p * q; q = a.q * q; normalize();
    return *this;
  }
  rational &operator -= (const rational &a) {
    p = a.q * p - a.p * q; q = a.q * q; normalize();
    return *this;
  }
  rational &operator *= (const rational &a) {
    p *= a.p; q *= a.q; normalize();
    return *this;
  }
  rational &operator /= (const rational &a) {
    p *= a.q; q *= a.p; normalize();
    return *this;
  }
  rational &operator - () {
    p *= -1;
    return *this;
  }
};
rational operator + (const rational &a, const rational &b) {
  return rational(a) += b;
}
rational operator * (const rational &a, const rational &b) {
  return rational(a) *= b;
}
rational operator - (const rational &a, const rational &b) {
  return rational(a) -= b;
}
rational operator / (const rational &a, const rational &b) {
  return rational(a) /= b;
}
bool operator < (const rational &a, const rational &b) { // avoid overflow
  return (long double) a.p * b.q < (long double) a.q * b.p;
}
bool operator <= (const rational &a, const rational &b) {
  return !(b < a);
}
bool operator > (const rational &a, const rational &b) {
  return b < a;
}
bool operator >= (const rational &a, const rational &b) {
  return !(a < b);
}
bool operator == (const rational &a, const rational &b) {
  return !(a < b) && !(b < a);
}
bool operator != (const rational &a, const rational &b) {
  return (a < b) || (b < a);
}
rational abs(rational in) {
  rational ret = in;
  ret.p = abs(ret.p);
  ret.q = abs(ret.q);
  return ret;
}

ll digit(ll a) {
    ll ok = 1;
    ll ng = 19;
    while(ng - ok > 1) {
        ll mid = (ok + ng) / 2;
        if(beki[mid-1] <= a) ok = mid;
        else ng = mid;
    }
    return ok;
}

vector<rational> field[341];
ll bi[100050], ai[100050];
rational br[100050], ar[100050];

int main() {
    //cerr << SqrtM << " " << WM << " " << SqrtM * WM << endl;
    beki[0] = 1;
    for(int i = 1; i < 20; i++) {
        beki[i] = beki[i-1] * 10;
    }
    for(int i = 0; i <= 300000; i++) ans[i] = 'x';
    cin >> N >> M;
    for(int i = 0; i < N; i++) {
        cin >> a[i];
        ai[i] = digit(a[i]);
        ar[i] = rational(a[i], beki[ai[i] - 1]);
    }
    for(int i  = 0; i < M; i++) {
        cin >> b[i];
        ll m = i / SqrtM;
        ll D = digit(b[i]);
        zero[m] += D - 1;
        number[m]++;
        field[m].push_back(rational(b[i], beki[D-1]));
        bi[i] = digit(b[i]);
        br[i] = rational(b[i], beki[bi[i] - 1]);
        /*
        for(int j = 0; j < N; j++) {
            ll m = i / SqrtM;
            //cerr << i << " " << j << " " << m << " " << digit(a[j] * b[i]) << endl;
            num[j][m] += digit(a[j] * b[i]);
            //field[j][m].push_back(a[j] * b[i]);
        }
        */
    }
    for(int m = 0; m < WM; m++) sort(field[m].begin(), field[m].end());
    for(int i = 0; i < N; i++) {
        for(int j = 0; j < WM; j++) {
        //for(int j = 0; j < 1; j++) {
            num[i][j] = zero[j];
            //cerr << i << " " << j << " " << num[i][j] << endl;
            ll D = digit(a[i]);
            num[i][j] += D * number[j];
            //cerr << i << " " << j << " " << num[i][j] << endl;
            auto itr = lower_bound(field[j].begin(), field[j].end(), rational(beki[D], a[i]));
            num[i][j] += distance(itr, field[j].end());
            //cerr << i << " " << j << " " << num[i][j] << endl;
            /*
            for(int k = 2; k <= 19; k++) {
                ll val = (beki[k-1] + a[i] - 1) / a[i];
                auto itr = lower_bound(field[j].begin(), field[j].end(), val);
                num[i][j] += distance(itr, field[j].end());
                //cerr << i << " " << j << " " << k << " " << " " << val << " " << num[i][j] << endl;
            }
            */
            //cerr << i << " " << j << " " << num[i][j] << endl;
        }
    }
    //*
    if(N >10000 or M > 10000) {
        cout << -1 << endl;
        return 0;
    }
    //*/
    cin >> Q;
    d.resize(Q);
    for(int i = 0; i < Q; i++) {
        cin >> d[i].first;
        d[i].second = i;
    }
    sort(d.begin(), d.end());
    //for(auto v : d) cerr << v.first << " " << v.second << endl;
    ll index = 0;
    ll nownum = 0;
    for(int n = 0; n < N; n++) {
        for(int m = 0; m < WM; m++) {
            while(true) {
                if(index >= 10000) return 0;
                if(index > d.size()) break;
                if(nownum + num[n][m] < d[index].first) {
                    nownum += num[n][m];
                    break;
                }
                //cerr << "index" << index << " " << d[index].first << " " << nownum << " " << n << " " << m << " " << num[n][m] << endl;
                ll now = nownum;
                for(int j = SqrtM * m; ;) {
                    ll D = ai[n] + bi[j] - 1;
                    if(ar[n] * br[j] >= 10) D++;
                    //cerr << n << " " << j << " " << D << endl;
                    if(now + D < d[index].first) {
                        now += D;
                        j++;
                        continue;
                    }
                    //cerr << index << " " << n << " " << j << " " << now << endl;
                    //ll D = digit(a[n] * b[j]);
                    ll rest = d[index].first - now;
                    ans[d[index].second] = (char)('0' + ((a[n] * b[j]) / beki[D - rest] % 10)); 
                    break;
                }
                index++;
            }
        }
    }
    for(int i = 0; i < Q; i++) {
        cout << ans[i];
    }
    cout << endl;
}
accuracy: 0.17647058823529413
time_ms: 1890
memory_kb: 277324
final_rank: 20

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> l_l;
ll N, M;
ll a[100050], b[100050];
ll beki[20];
ll Q;
vector<l_l> d;
ll SqrtM = 1000;
ll WM = (100000 + SqrtM - 1) / SqrtM;
char ans[300050];
ll num[100050][341];
ll number[340];
ll zero[341];

ll gcd(ll a, ll b) {
    if(a < b) swap(a, b);
    if(a % b == 0) return b;
    return gcd(b, a % b);
}

struct rational {
  ll p, q;
  void normalize() { // keep q positive
    if (q < 0) p *= -1, q *= -1;
    ll d = gcd(p < 0 ? -p : p, q);
    if (d == 0) p = 0,  q = 1;
    else        p /= d, q /= d;
  }
  rational(ll p, ll q = 1) : p(p), q(q) {
    normalize();
  }
  rational() {
      p = 0;
      q = 1;
  }
  rational &operator += (const rational &a) {
    p = a.q * p + a.p * q; q = a.q * q; normalize();
    return *this;
  }
  rational &operator -= (const rational &a) {
    p = a.q * p - a.p * q; q = a.q * q; normalize();
    return *this;
  }
  rational &operator *= (const rational &a) {
    p *= a.p; q *= a.q; normalize();
    return *this;
  }
  rational &operator /= (const rational &a) {
    p *= a.q; q *= a.p; normalize();
    return *this;
  }
  rational &operator - () {
    p *= -1;
    return *this;
  }
};
rational operator + (const rational &a, const rational &b) {
  return rational(a) += b;
}
rational operator * (const rational &a, const rational &b) {
  return rational(a) *= b;
}
rational operator - (const rational &a, const rational &b) {
  return rational(a) -= b;
}
rational operator / (const rational &a, const rational &b) {
  return rational(a) /= b;
}
bool operator < (const rational &a, const rational &b) { // avoid overflow
  return (long double) a.p * b.q < (long double) a.q * b.p;
}
bool operator <= (const rational &a, const rational &b) {
  return !(b < a);
}
bool operator > (const rational &a, const rational &b) {
  return b < a;
}
bool operator >= (const rational &a, const rational &b) {
  return !(a < b);
}
bool operator == (const rational &a, const rational &b) {
  return !(a < b) && !(b < a);
}
bool operator != (const rational &a, const rational &b) {
  return (a < b) || (b < a);
}
rational abs(rational in) {
  rational ret = in;
  ret.p = abs(ret.p);
  ret.q = abs(ret.q);
  return ret;
}

ll digit(ll a) {
    ll ok = 1;
    ll ng = 19;
    while(ng - ok > 1) {
        ll mid = (ok + ng) / 2;
        if(beki[mid-1] <= a) ok = mid;
        else ng = mid;
    }
    return ok;
}

vector<rational> field[341];
ll bi[100050], ai[100050];
rational br[100050], ar[100050];

int main() {
    //cerr << SqrtM << " " << WM << " " << SqrtM * WM << endl;
    beki[0] = 1;
    for(int i = 1; i < 20; i++) {
        beki[i] = beki[i-1] * 10;
    }
    for(int i = 0; i <= 300000; i++) ans[i] = 'x';
    cin >> N >> M;
    for(int i = 0; i < N; i++) {
        cin >> a[i];
        ai[i] = digit(a[i]);
        ar[i] = rational(a[i], beki[ai[i] - 1]);
    }
    for(int i  = 0; i < M; i++) {
        cin >> b[i];
        ll m = i / SqrtM;
        ll D = digit(b[i]);
        zero[m] += D - 1;
        number[m]++;
        field[m].push_back(rational(b[i], beki[D-1]));
        bi[i] = digit(b[i]);
        br[i] = rational(b[i], beki[bi[i] - 1]);
        /*
        for(int j = 0; j < N; j++) {
            ll m = i / SqrtM;
            //cerr << i << " " << j << " " << m << " " << digit(a[j] * b[i]) << endl;
            num[j][m] += digit(a[j] * b[i]);
            //field[j][m].push_back(a[j] * b[i]);
        }
        */
    }
    for(int m = 0; m < WM; m++) sort(field[m].begin(), field[m].end());
    for(int i = 0; i < N; i++) {
        for(int j = 0; j < WM; j++) {
        //for(int j = 0; j < 1; j++) {
            num[i][j] = zero[j];
            //cerr << i << " " << j << " " << num[i][j] << endl;
            ll D = digit(a[i]);
            num[i][j] += D * number[j];
            //cerr << i << " " << j << " " << num[i][j] << endl;
            auto itr = lower_bound(field[j].begin(), field[j].end(), rational(beki[D], a[i]));
            num[i][j] += distance(itr, field[j].end());
            //cerr << i << " " << j << " " << num[i][j] << endl;
            /*
            for(int k = 2; k <= 19; k++) {
                ll val = (beki[k-1] + a[i] - 1) / a[i];
                auto itr = lower_bound(field[j].begin(), field[j].end(), val);
                num[i][j] += distance(itr, field[j].end());
                //cerr << i << " " << j << " " << k << " " << " " << val << " " << num[i][j] << endl;
            }
            */
            //cerr << i << " " << j << " " << num[i][j] << endl;
        }
    }
    //*
    if(N >10000 or M > 10000) {
        cout << -1 << endl;
        return 0;
    }
    //*/
    cin >> Q;
    d.resize(Q);
    for(int i = 0; i < Q; i++) {
        cin >> d[i].first;
        d[i].second = i;
    }
    sort(d.begin(), d.end());
    //for(auto v : d) cerr << v.first << " " << v.second << endl;
    ll index = 0;
    ll nownum = 0;
    for(int n = 0; n < N; n++) {
        for(int m = 0; m < WM; m++) {
            while(true) {
                if(index >= 100000) return 0;
                if(index > d.size()) break;
                if(nownum + num[n][m] < d[index].first) {
                    nownum += num[n][m];
                    break;
                }
                //cerr << "index" << index << " " << d[index].first << " " << nownum << " " << n << " " << m << " " << num[n][m] << endl;
                ll now = nownum;
                for(int j = SqrtM * m; ;) {
                    ll D = ai[n] + bi[j] - 1;
                    if(ar[n] * br[j] >= 10) D++;
                    //cerr << n << " " << j << " " << D << endl;
                    if(now + D < d[index].first) {
                        now += D;
                        j++;
                        continue;
                    }
                    //cerr << index << " " << n << " " << j << " " << now << endl;
                    //ll D = digit(a[n] * b[j]);
                    ll rest = d[index].first - now;
                    ans[d[index].second] = (char)('0' + ((a[n] * b[j]) / beki[D - rest] % 10)); 
                    break;
                }
                index++;
            }
        }
    }
    for(int i = 0; i < Q; i++) {
        cout << ans[i];
    }
    cout << endl;
}
accuracy: 0.17647058823529413
time_ms: 1880
memory_kb: 277356
final_rank: 19