leetcode(891) 子序列宽度之和

题目链接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;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值