1498. 满足条件的子序列数目
给你一个整数数组 nums 和一个整数 target 。
请你统计并返回 nums 中能满足其最小元素与最大元素的 和 小于或等于 target 的 非空 子序列的数目。
由于答案可能很大,请将结果对 10^9 + 7 取余后返回。
1.枚举法
vmin<=vmax<=target-vmin
vmin2<=target
枚举vmin,固定vmin,vmax为vmin到【target-vmin】,对剩余元素做二分查找,找到vmax个数,由于vmin2<=target,每个vmin贡献2^(x-1)
可以先预处理出所有 2^i ( mod( 10 ^9)
+7) 的值,然后对原序列进行排序预处理。
在实现中,我们会用到取模来防止答案过大而溢出,这里需要用这样的小技巧来处理:
(a+b)modP=[(amodP)+(bmodP)]modP
(a×b)modP=[(amodP)×(bmodP)]modP
class Solution {
public:
static constexpr int P = int(1E9) + 7;
static constexpr int MAX_N = int(1E5) + 5;
int f[MAX_N];
void pretreatment() {
f[0] = 1;
for (int i = 1; i < MAX_N; ++i) {
f[i] = (long long)f[i - 1] * 2 % P;
}
}
int numSubseq(vector<int>& nums, int target) {
pretreatment();
sort(nums.begin(), nums.end());
int ans = 0;
for (int i = 0; i < nums.size() && nums[i] * 2 <= target; ++i) {
int maxValue = target - nums[i];
int pos = upper_bound(nums.begin(), nums.end(), maxValue) - nums.begin() - 1;
int contribute = (pos >= i) ? f[pos - i] : 0;
ans = (ans + contribute) % P;
}
return ans;
}
};
排序+二分查找+快速幂
class Solution { //C++
int mod = 1e9+7;
public:
int numSubseq(vector<int>& nums, int target) {
sort(nums.begin(),nums.end());
int i = 0, j;
unsigned long long count = 0;
for(i = 0; i < nums.size(); ++i)
{
if(nums[i] > target/2+1)
break;
j = bs(nums,target-nums[i]);
if(j != -1 && j >= i)
count = (count+mypow(j-i))%mod;
}
return count;
}
int bs(vector<int>&a,int t)
{
int left = 0;
int right = a.size()-1;
int mid;
while(left<=right)
{
mid = (left+right)/2;
if(a[mid]>t)
{
right = mid -1;
}
else
{
if(mid == a.size()-1 || a[mid+1]>t )
{
return mid;
}
else
{
left = mid + 1;
}
}
}
return -1;
}
int mypow(int n)
{
long long s = 1, p = 2;
while(n)
{
if(n&1)
s *= p, s %= mod;
p *= p;
p %= mod;
n /= 2;
}
return s;
}
};