comments | difficulty | edit_url | rating | source | tags | |||
---|---|---|---|---|---|---|---|---|
true |
困难 |
2859 |
第 130 场双周赛 Q4 |
|
一个非负整数 x
的 强数组 指的是满足元素为 2 的幂且元素总和为 x
的最短有序数组。下表说明了如何确定 强数组 的示例。可以证明,x
对应的强数组是独一无二的。
数字 | 二进制表示 | 强数组 |
---|---|---|
1 | 00001 | [1] |
8 | 01000 | [8] |
10 | 01010 | [2, 8] |
13 | 01101 | [1, 4, 8] |
23 | 10111 | [1, 2, 4, 16] |
我们将每一个升序的正整数 i
(即1,2,3等等)的 强数组 连接得到数组 big_nums
,big_nums
开始部分为 [1, 2, 1, 2, 4, 1, 4, 2, 4, 1, 2, 4, 8, ...]
。
给你一个二维整数数组 queries
,其中 queries[i] = [fromi, toi, modi]
,你需要计算 (big_nums[fromi] * big_nums[fromi + 1] * ... * big_nums[toi]) % modi
。
请你返回一个整数数组 answer
,其中 answer[i]
是第 i
个查询的答案。
示例 1:
输入:queries = [[1,3,7]]
输出:[4]
解释:
只有一个查询。
big_nums[1..3] = [2,1,2]
。它们的乘积为 4。结果为 4 % 7 = 4
。
示例 2:
输入:queries = [[2,5,3],[7,7,4]]
输出:[2,2]
解释:
有两个查询。
第一个查询:big_nums[2..5] = [1,2,4,1]
。它们的乘积为 8 。结果为 8 % 3 = 2
。
第二个查询:big_nums[7] = 2
。结果为 2 % 4 = 2
。
提示:
1 <= queries.length <= 500
queries[i].length == 3
0 <= queries[i][0] <= queries[i][1] <= 1015
1 <= queries[i][2] <= 105
连续的正整数数字对应的强整数数组连接得到数组
因此,我们不妨将
接下来,就是根据下标
我们根据题目描述,列出数字
8( |
4( |
2( |
( |
|
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 1 |
2 | 0 | 0 | 1 | 0 |
3 | 0 | 0 | 1 | 1 |
4 | 0 | 1 | 0 | 0 |
5 | 0 | 1 | 0 | 1 |
6 | 0 | 1 | 1 | 0 |
7 | 0 | 1 | 1 | 1 |
8 | 1 | 0 | 0 | 0 |
9 | 1 | 0 | 0 | 1 |
10 | 1 | 0 | 1 | 0 |
11 | 1 | 0 | 1 | 1 |
12 | 1 | 1 | 0 | 0 |
13 | 1 | 1 | 0 | 1 |
14 | 1 | 1 | 1 | 0 |
将数字按照
接下来,对于任何数字,我们考虑如何计算其强数组的个数和幂次之和。我们可以通过二进制的方式,从最高位开始,诸位计算。例如,对于数字
最后,我们可以根据
时间复杂度
m = 50
cnt = [0] * (m + 1)
s = [0] * (m + 1)
p = 1
for i in range(1, m + 1):
cnt[i] = cnt[i - 1] * 2 + p
s[i] = s[i - 1] * 2 + p * (i - 1)
p *= 2
def num_idx_and_sum(x: int) -> tuple:
idx = 0
total_sum = 0
while x:
i = x.bit_length() - 1
idx += cnt[i]
total_sum += s[i]
x -= 1 << i
total_sum += (x + 1) * i
idx += x + 1
return (idx, total_sum)
def f(i: int) -> int:
l, r = 0, 1 << m
while l < r:
mid = (l + r + 1) >> 1
idx, _ = num_idx_and_sum(mid)
if idx < i:
l = mid
else:
r = mid - 1
total_sum = 0
idx, total_sum = num_idx_and_sum(l)
i -= idx
x = l + 1
for _ in range(i):
y = x & -x
total_sum += y.bit_length() - 1
x -= y
return total_sum
class Solution:
def findProductsOfElements(self, queries: List[List[int]]) -> List[int]:
return [pow(2, f(right + 1) - f(left), mod) for left, right, mod in queries]
class Solution {
private static final int M = 50;
private static final long[] cnt = new long[M + 1];
private static final long[] s = new long[M + 1];
static {
long p = 1;
for (int i = 1; i <= M; i++) {
cnt[i] = cnt[i - 1] * 2 + p;
s[i] = s[i - 1] * 2 + p * (i - 1);
p *= 2;
}
}
private static long[] numIdxAndSum(long x) {
long idx = 0;
long totalSum = 0;
while (x > 0) {
int i = Long.SIZE - Long.numberOfLeadingZeros(x) - 1;
idx += cnt[i];
totalSum += s[i];
x -= 1L << i;
totalSum += (x + 1) * i;
idx += x + 1;
}
return new long[] {idx, totalSum};
}
private static long f(long i) {
long l = 0;
long r = 1L << M;
while (l < r) {
long mid = (l + r + 1) >> 1;
long[] idxAndSum = numIdxAndSum(mid);
long idx = idxAndSum[0];
if (idx < i) {
l = mid;
} else {
r = mid - 1;
}
}
long[] idxAndSum = numIdxAndSum(l);
long totalSum = idxAndSum[1];
long idx = idxAndSum[0];
i -= idx;
long x = l + 1;
for (int j = 0; j < i; j++) {
long y = x & -x;
totalSum += Long.numberOfTrailingZeros(y);
x -= y;
}
return totalSum;
}
public int[] findProductsOfElements(long[][] queries) {
int n = queries.length;
int[] ans = new int[n];
for (int i = 0; i < n; i++) {
long left = queries[i][0];
long right = queries[i][1];
long mod = queries[i][2];
long power = f(right + 1) - f(left);
ans[i] = qpow(2, power, mod);
}
return ans;
}
private int qpow(long a, long n, long mod) {
long ans = 1 % mod;
for (; n > 0; n >>= 1) {
if ((n & 1) == 1) {
ans = ans * a % mod;
}
a = a * a % mod;
}
return (int) ans;
}
}
using ll = long long;
const int m = 50;
ll cnt[m + 1];
ll s[m + 1];
ll p = 1;
auto init = [] {
cnt[0] = 0;
s[0] = 0;
for (int i = 1; i <= m; ++i) {
cnt[i] = cnt[i - 1] * 2 + p;
s[i] = s[i - 1] * 2 + p * (i - 1);
p *= 2;
}
return 0;
}();
pair<ll, ll> numIdxAndSum(ll x) {
ll idx = 0;
ll totalSum = 0;
while (x > 0) {
int i = 63 - __builtin_clzll(x);
idx += cnt[i];
totalSum += s[i];
x -= 1LL << i;
totalSum += (x + 1) * i;
idx += x + 1;
}
return make_pair(idx, totalSum);
}
ll f(ll i) {
ll l = 0;
ll r = 1LL << m;
while (l < r) {
ll mid = (l + r + 1) >> 1;
auto idxAndSum = numIdxAndSum(mid);
ll idx = idxAndSum.first;
if (idx < i) {
l = mid;
} else {
r = mid - 1;
}
}
auto idxAndSum = numIdxAndSum(l);
ll totalSum = idxAndSum.second;
ll idx = idxAndSum.first;
i -= idx;
ll x = l + 1;
for (int j = 0; j < i; ++j) {
ll y = x & -x;
totalSum += __builtin_ctzll(y);
x -= y;
}
return totalSum;
}
ll qpow(ll a, ll n, ll mod) {
ll ans = 1 % mod;
a = a % mod;
while (n > 0) {
if (n & 1) {
ans = ans * a % mod;
}
a = a * a % mod;
n >>= 1;
}
return ans;
}
class Solution {
public:
vector<int> findProductsOfElements(vector<vector<ll>>& queries) {
int n = queries.size();
vector<int> ans(n);
for (int i = 0; i < n; ++i) {
ll left = queries[i][0];
ll right = queries[i][1];
ll mod = queries[i][2];
ll power = f(right + 1) - f(left);
if (power < 0) {
power += mod;
}
ans[i] = static_cast<int>(qpow(2, power, mod));
}
return ans;
}
};
const m = 50
var cnt [m + 1]int64
var s [m + 1]int64
var p int64 = 1
func init() {
cnt[0] = 0
s[0] = 0
for i := 1; i <= m; i++ {
cnt[i] = cnt[i-1]*2 + p
s[i] = s[i-1]*2 + p*(int64(i)-1)
p *= 2
}
}
func numIdxAndSum(x int64) (int64, int64) {
var idx, totalSum int64
for x > 0 {
i := 63 - bits.LeadingZeros64(uint64(x))
idx += cnt[i]
totalSum += s[i]
x -= 1 << i
totalSum += (x + 1) * int64(i)
idx += x + 1
}
return idx, totalSum
}
func f(i int64) int64 {
l, r := int64(0), int64(1)<<m
for l < r {
mid := (l + r + 1) >> 1
idx, _ := numIdxAndSum(mid)
if idx < i {
l = mid
} else {
r = mid - 1
}
}
_, totalSum := numIdxAndSum(l)
idx, _ := numIdxAndSum(l)
i -= idx
x := l + 1
for j := int64(0); j < i; j++ {
y := x & -x
totalSum += int64(bits.TrailingZeros64(uint64(y)))
x -= y
}
return totalSum
}
func qpow(a, n, mod int64) int64 {
ans := int64(1) % mod
a = a % mod
for n > 0 {
if n&1 == 1 {
ans = (ans * a) % mod
}
a = (a * a) % mod
n >>= 1
}
return ans
}
func findProductsOfElements(queries [][]int64) []int {
ans := make([]int, len(queries))
for i, q := range queries {
left, right, mod := q[0], q[1], q[2]
power := f(right+1) - f(left)
ans[i] = int(qpow(2, power, mod))
}
return ans
}