【问题标题】:Range queries on a binary string?对二进制字符串进行范围查询?
【发布时间】:2021-02-10 00:13:57
【问题描述】:

二进制-十进制

我们得到一个长度为n二进制字符串 S,其中每个字符都是'1'或'0'

我们被要求对字符串执行几个查询。

在每个查询中,我们都会得到整数 LR。 而且我们必须用十进制表示来告诉子字符串S[l..r]的值。

示例测试用例:

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)

约束

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

由于数字可能很大,我们需要以 10^9 + 7 为模打印。

接近

所以基本上我们需要将二进制表示的子字符串 S[l..r] 转换为十进制。

预先计算S[i...n-1]对所有i:[0, n-1]的结果 strong> 在 数组 B 中。 所以现在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;

通过上述方法,只有示例测试用例通过,所有其他案例都给出错误答案(WA)

我什至尝试使用 Segment tree 来解决这个问题,但这也不起作用。

解决这个问题的正确方法是什么?

【问题讨论】:

  • 你从右边填B[],从左边填s[]?
  • @MBo,是的,这是一个错字,已修复,但仍然无法正常工作。

标签: c++ algorithm math data-structures modulus


【解决方案1】:

V[k]定义为S的数字值,从k第一个开始。

然后是子字符串S[l..r] = (V[l] - V[r+1]) / 2^(n - r - 1)的值。 (类似的东西,我可能有一个错误。玩一些小例子。)

现在关于10^9 + 7 的有用事实是它是一个素数。 (前 10 位素数。)这意味着除以 2 与乘以 2^(10^9 + 5) 相同。这是一个常数,您可以通过重复平方来计算。使用重复平方可以非常有效地将该常数提高到高幂。

这样您就可以为V 创建一个查找表,然后及时查询O(log(n))

【讨论】:

  • 对于那些想知道2^(10^9 + 5)2 模的乘法逆元10^9 + 7 的更具体原因的人:对于任何素数p,素数域的乘法组{1, ..., p-1} Z/pZ(即由加法和乘法形成的整数字段{0, ..., p-1}mod p)是循环的,即x^(p-1) = 1 mod p 是所有1 &lt;= x &lt;= p - 1。两边乘以x^(-1)x^(-1) = x^(p-2) mod p。这适用于所有素数p 和所有1 &lt;= x &lt;= p-1。在这种情况下,2^(-1) = 2^(10^9 + 7 - 2) mod (10^9 + 7).
  • @EvilTak ,所以基本上我们使用的公式是正确的,但是模(%)在这个公式中使用除法运算的方式会产生错误的答案。我不知道模在除法和乘法逆运算中是如何工作的。你能提供我可以从基础学习模乘逆的任何资源吗?
  • @tusharRawat 不是除以 2^(n - r - 1),而是乘以它的模逆 (2^(10^9 + 5)) ^ (n - r - 1)。注意2^(10^9 + 5) = 500000004 mod (10^9 + 7),所以S[l..r] = (V[l] - V[r+1]) * 500000004^(n - r - 1) mod (10^9 + 7)
【解决方案2】:

这似乎与常规求和范围查询相同,除了(1)我们需要存储部分和 mod 10^9 + 7,(2)在检索期间,我们需要“移动”完整的相关部分将其右侧部分的长度相加。在这种情况下,“移位”意味着乘以 2^(length_of_suffix) mod 10^9 + 7。当然,对部分求和 mod 10^9 + 7。

但是 btilly 的 answer 似乎要简单得多:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-15
    • 1970-01-01
    • 2012-03-13
    • 2011-07-11
    • 1970-01-01
    • 2017-03-22
    • 2016-02-26
    相关资源
    最近更新 更多