Range queries on a binary string?

444 views Asked by At

Binary-Decimal

We are given a binary string S of length n, in which each character is either '1' or '0'.

And we are asked to perform several queries on the string.

In each query we are given integers L and R. And we have to tell the value of sub-string S[l..r], in decimal representation.

Sample testcase:

Input:

1011 (string S)
5    (number of queries)
1 1  (l, r)
2 2
1 2
2 4
1 4

Output:
1      (1 * 2^0 == 1)
0
2
3      (0 * 2^2 + 1 * 2^1 + 1 * 2^0)
11     (1 * 2^3 + 0 * 2^2 + 1 * 2^1 + 1 * 2^0 = 11)

Constraints

1 < N < 10^5
1 < Q < 10^5

As the number can be very large, we are required to print it modulo 10^9 + 7.

Approach

So basically we need to convert binary representation sub-string S[l..r] in it's decimal.

I pre-computed the results of S[i...n-1] for all i:[0, n-1] in array B. So now B[i] represents the decimal number representation of sub-string S[i..n-1].

vector<int> pow(1e5, 1);
for(int i = 1; i < 1e5; i++) {
    pow[i] = (pow[i - 1] * 2) % mod;
}

string s;
getline(cin, s);
vector<int> B(n, 0);
int prev = 0;
for(int i = 0; i < n; i++) {
    B[(n - 1) - i] = (prev + (s[(n - 1) - i] == '1' ? pow[i] : 0)) % mod;
    prev = B[(n - 1) - i];
}

while(q--) {
    int l, r;
    cin >> l >> r;
    cout << ((B[l] - (r + 1 < n ? B[r + 1] : 0) + mod) % mod) / pow[n - (r + 1)]<< "\n";
}

return 0;

With the above approach only sample testcase got passed and all other cases are giving the wrong answers(WA).

I even tried using Segment tree for this problem but that is also not working.

What is the correct approach to solve this problem ?

2

There are 2 answers

3
btilly On BEST ANSWER

Define V[k] to be the value of the digits of S starting with the kth one.

Then the value of the substring S[l..r] = (V[l] - V[r+1]) / 2^(n - r - 1). (Something like that, I may have an off by one error. Play with small examples.)

Now the useful fact about 10^9 + 7 is that it is a prime. (The first 10 digit prime.) Which means that dividing by 2 is the same as multiplying by 2^(10^9 + 5). Which is a constant that you can figure out with repeated squaring. And raising that constant to a high power can be done very efficiently using repeated squaring.

With this you can create a lookup table for V, and then do your queries in time O(log(n)).

0
גלעד ברקן On

This seems the same as regular sum range-queries, except (1) we need to store the partial sums mod 10^9 + 7, (2) during retrieval, we need to "shift" the relevant sections of the full sum by the length of the sections on their right. To "shift" in this case would mean multiplying by 2^(length_of_suffix) mod 10^9 + 7. And of course sum the sections mod 10^9 + 7.

But btilly's answer seems much simpler :)