每个集合实际上起作用的就是最大和最小的两个数,根据这个把每个集合按跨度分类
跨度就是所有数排好序后,集合中最大和最小的数的间隔
所有的集合可以分为跨度从1~n-1的几类
举例,有5个数,1,2,3,4,5,那么最小和最大数为2和4的集合跨度为2
确定最大最小数,且跨度为i的集合有2^(i-1)种,因为最大最小数之间的数的个数为 i-1
那么可以统计所有跨度为 i 的集合的和(最大数减去最小数): sum[i]
把所有 sum[i]*2^(i-1) 加起来就是最终答案
统计sum[i]的公式见代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const ll MOD=1e9+7;
const int N=300000+10;
ll sum[N];
ll a[N];
ll expow(ll a,ll b,ll mod)
{
ll ret=1;
while(b)
{
if(b&1)
{
ret*=a;
ret%=mod;
}
a*=a;
a%=mod;
b>>=1;
}
return ret;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lld",&a[i]);
sort(a,a+n);
if(n==1)
{
printf("0\n");
return 0;
}
if(n==2)
{
printf("%lld\n",a[1]-a[0]);
return 0;
}
sum[1]=a[n-1]-a[0];
for(int i=2;i<=n/2;i++)
sum[i]=(a[n-i]-a[i-1]+sum[i-1])%MOD;
for(int i=n/2+1;i<n;i++)
sum[i]=sum[n-i];
ll ans=sum[1],t;
for(int i=2;i<n;i++)
{
t=sum[i];
ans=(ans+t*expow(2,i-1,MOD)%MOD)%MOD;
}
printf("%lld\n",ans);
return 0;
}