所有子序列的最大最小差值之和
int sumSubseqWidths(vector<int>& A) {
// 子序列的最大最小值,与顺序无关,排序数组
// 比A[i]大的数有N-1-i个,A[i]作最小值的子序列有2^(N-1-i)个,A[i]对ans贡献2^(N-1-i)*(-A[i])
// 比A[i]小的数有i个,A[i]作最大值的子序列有2^i个,对ans贡献2^i*A[i]
// 所以,A[i]对ans贡献 A[i] * (2^i - 2^(N-1-i))
sort(A.begin(), A.end());
const int N = A.size(), MOD = 1e9 + 7;
vector<int> pow2(N);
pow2[0] = 1;
for (int i = 1; i < N; i++) {
pow2[i] = (pow2[i-1] << 1) % MOD;
}
int ans = 0;
for (int i = 0; i < N; i++) {
ans = (ans + (long)A[i] * (pow2[i] - pow2[N-1-i])) % MOD;
}
return ans;
}
所有满足 子序列最大最小之和<=target 的子序列个数
int numSubseq(vector<int>& A, int target) {
// 子序列的最大最小值与顺序无关,排序数组
sort(A.begin(), A.end());
// 预先计算pow2[]
const int N = A.size(), MOD = 1e9 + 7;
vector<int> pow2(N);
pow2[0] = 1;
for (int i = 1; i < N; i++) {
pow2[i] = (pow2[i-1] << 1) % MOD;
}
// 对A[i],找A[i]+A[j]<=target的最大j,两指针法
int ans = 0;
for (int i = 0, j = N - 1; i <= j; ) {
if (A[i] + A[j] > target) {
j--;
} else {
// 非空子序列,选了A[i]后,(i..j]间的数可选或不选,有2^(j-i)种可能
ans = (ans + pow2[j-i]) % MOD;
i++;
}
}
return ans;
}
所有奇数长子段的总和
int sumOddLengthSubarrays(vector<int>& A) {
// 看A[i]对奇数长子段贡献了多少值
// 左边包含A[i]的子段A[..i]有i+1个,右边包含A[i]的子段A[i..]有N-i个,包含A[i]的子段共(i+1)*(N-i)个。
// 设包含A[i]的奇数子段有odd个,偶数子段有even个,由举例归纳的、应该没错的结论为 odd=even或even+1。
// 注:比如举例统计[1 2 3 4 5]中包含2的长度1子段数、长度2子段数、长度3子段数...,
// 所以奇数长子段有 odd = ((i+1)*(N-i)+1)/2个
const int N = A.size();
int ans = 0;
for (int i = 0; i < N; i++) {
ans += ((i+1)*(N-i)+1)/2 * A[i];
}
return ans;
}
联想:所有子段最小值的和