[分治] Codeforces#415 (Div. 1) 809A. Do you want a date?

题意

给出一个n个元素的数集。
求这个集合的所有非空子集的权值和。一个集合 A 的权值定义为:maxi,jA |ij|

题解

集合的权值只由最大和最小的两个数决定,所以可以想到给 n 个数排序,题目转换为:
定义一个区间 [L,R] 的权值为 (a[R]a[L])2RL1 。求所有子区间权值和。
这个就分治乱搞就好了。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL maxn=300015, MOD=1000000007;
int n,ans;
LL a[maxn],pw[maxn],inv_pw[maxn];

void Solve(int L,int R){
    if(R-L+1<=1) return;
    int mid=(L+R)>>1;
    Solve(L,mid); Solve(mid+1,R);
    LL sum1=0,sum2=0;
    for(int i=mid+1;i<=R;i++) sum1=(sum1+pw[i])%MOD, sum2=(sum2+pw[i]*a[i]%MOD)%MOD;
    for(int i=L;i<=mid;i++){
        int res=inv_pw[i+1]* ((sum2+(MOD-a[i])*sum1%MOD)%MOD) %MOD;
        ans=(ans+res)%MOD;
    }
}
int main(){
//  freopen("A.in","r",stdin);
//  freopen("A.out","w",stdout);
    pw[0]=inv_pw[0]=1;
    for(int i=1;i<=300005;i++) pw[i]=pw[i-1]*2%MOD, inv_pw[i]=inv_pw[i-1]*((MOD+1)/2)%MOD;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%I64d",&a[i]);
    sort(a+1,a+1+n);
    Solve(1,n);
    printf("%d\n",ans);
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值