本文已参与「新人创作礼」活动,一起开启掘金创作之路。
2354. 优质数对的数目
示例 1:
输入:nums = [1,2,3,1], k = 3
输出:5
解释:有如下几个优质数对:
- (3, 3):(3 AND 3) 和 (3 OR 3) 的二进制表示都等于 (11) 。值为 1 的位数和等于 2 + 2 = 4 ,大于等于 k = 3 。
- (2, 3) 和 (3, 2): (2 AND 3) 的二进制表示等于 (10) ,(2 OR 3) 的二进制表示等于 (11) 。值为 1 的位数和等于 1 + 2 = 3 。
- (1, 3) 和 (3, 1): (1 AND 3) 的二进制表示等于 (01) ,(1 OR 3) 的二进制表示等于 (11) 。值为 1 的位数和等于 1 + 2 = 3 。
所以优质数对的数目是 5 。
示例 2:
输入:nums = [5,1,1], k = 10
输出:0
解释:该数组中不存在优质数对。
数据范围
1 <= nums.length <= 10^51 <= nums[i] <= 10^91 <= k <= 60
思路
根据题目意思,那么每一个数字的贡献只有两个
一个是自己和自己,另一个是自己和其他人
自己和自己只形成一个
自己和前面的其他人则可以形成 对
树状数组动态修改 进行前缀和统计 这个数前面有多少个数满足要求的就是了
时间复杂度
当然,要记得处理一下小细节,就是得不重复。所以我们需要排序去重 然后再算优质数对的个数。
class Solution {
public:
long long countExcellentPairs(vector<int>& g, int k) {
using ll = long long;
ll ans{};
sort(g.begin(), g.end());
g.erase(unique(g.begin(), g.end()), g.end());
vector<int> ve(66);
int n = 65;
auto low = [](int x) {return x & -x;};
auto add = [&](int x) {for (int i = x; i <= n; i += low(i)) ve[i] += 1;};
auto get = [&](int x) {
if (x <= 0) return 0;
int res = 0; for (int i = x; i; i -= low(i)) res += ve[i];
return res;
};
auto cala = [&](int x) {
int res = 0; while (x) {if (x&1) res ++; x >>= 1;}
return res;
};
for (int i = 0; i < g.size(); i ++) {
int siz = cala(g[i]);
if (siz + siz >= k) ans ++;
int val = get(n) - get(k - siz - 1);
ans += val * 2;
add(siz);
}
return ans;
}
};