简体   繁体   English

对二进制字符串进行范围查询?

[英]Range queries on a binary string?

Binary-Decimal二进制-十进制

We are given a binary string S of length n , in which each character is either '1' or '0' .我们得到一个长度为 n二进制字符串S ,其中每个字符都是'1' 或 '0'

And we are asked to perform several queries on the string.我们被要求对字符串执行几个查询。

In each query we are given integers L and R .在每个查询中,我们都给出了整数LR And we have to tell the value of sub-string S[l..r] , in decimal representation .我们必须告诉子串S[l..r] 的值,以十进制表示

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.由于数字可能非常大,我们需要以10^9 + 7 的模数打印它

Approach方法

So basically we need to convert binary representation sub-string S[l..r] in it's decimal.所以基本上我们需要将二进制表示子字符串 S[l..r] 转换为十进制。

I pre-computed the results of S[i...n-1] for all i:[0, n-1] in array B .预先计算数组 B 中所有i:[0, n-1]S[i...n-1]的结果。 So now B[i] represents the decimal number representation of sub-string S[i..n-1] .所以现在B[i]表示子串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) .使用上述方法,只有示例测试用例通过了,所有其他情况都给出了错误的答案(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 ?解决这个问题的正确方法是什么?

Define V[k] to be the value of the digits of S starting with the k th one.定义V[k]S从第k位开始的数字的值。

Then the value of the substring S[l..r] = (V[l] - V[r+1]) / 2^(n - r - 1) .然后子串的值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.现在关于10^9 + 7的有用事实是它是素数。 (The first 10 digit prime.) Which means that dividing by 2 is the same as multiplying by 2^(10^9 + 5) . (前 10 位素数。)这意味着除以 2 与乘以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)) .有了这个,您可以为V创建一个查找表,然后在O(log(n))时间内进行查询。

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.这似乎与常规和范围查询相同,除了(1)我们需要存储部分和 mod 10^9 + 7,(2)在检索期间,我们需要通过右边部分的长度。 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.在这种情况下,“移位”意味着乘以 2^(length_of_suffix) mod 10^9 + 7。当然,对部分 mod 10^9 + 7 求和。

But btilly's answer seems much simpler :)但是 btilly 的答案似乎要简单得多:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM