题目链接:https://leetcode.cn/problems/sum-of-subsequence-widths/description/
题意:给定一个整数数组 A ,考虑 A 的所有非空子序列。对于任意序列 S ,设 S 的宽度是 S 的最大元素和最小元素的差。返回 A 的所有子序列的宽度之和,由于答案可能非常大,请返回答案模 10^9+7。
思路:首先要想到改变数组的顺序对答案没有任何影响,因为一个子序列的最大值和最小值与它们所处的位置无关,例如[2,1,3]的子序列为[2],[1],[3],[2,1],[2,3],[1,3],[2,1,3]与[1,2,3]的子序列[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]最终结果是一样的。
所以我们按照递增排序后讨论,这样每个元素都比它左边大或相等(作为最大值),比它右边小(作为最小值),朴素的做法是枚举最小值的下标l和最大值的下标r(l<=r),但时间复杂度为O(N^2)
会超时。因此考虑将问题转化为每个元素对答案的贡献有多少,一个元素v[i]所处的位置为i,那么比它小的元素有i个,比它大的元素有n-i-1个,作为最大值的贡献为v[i]*pow(2,i)
,作为最小值的贡献为-v[i]*pow(2,n-i-1)
,结果就是每个数贡献值相加sum(v[i]*(pow(2,i)-pow(2,n-i-1)))
。
代码:
class Solution {
public:
int mod=1e9+7;
long long fpow[100005];
int sumSubseqWidths(vector<int>& v) {
fpow[0]=1;
int n=v.size();
long long ans=0;
for(int i=1;i<=1e5;i++) fpow[i]=(fpow[i-1]*2)%mod;
sort(v.begin(),v.end());
for(int i=0;i<n;i++){
ans=(ans+((fpow[i]-fpow[n-1-i])*v[i])%mod)%mod;
}
return ans;
}
};