题目描述
有这样一个经典问题:
给出一个长度为n的非负整数数组a。
每次可以选择数组中两个不同位置的数ai,aj(i ̸= j),将它们删除,然后再向数组中加入一个新的元素,值为ai + aj。
这样一次操作产生的代价是这个新元素的值,即ai + aj。
例如当前数组中的数为a = {1,1,3,1},选择a1 = 1,a4 = 1进行操作后,数组变为{1,3,2},代价为2。
一共会进行n − 1次操作,要求最小化代价之和。
这道题可以用经典的哈夫曼树算法解决,然而小D正在NOI考场上,根本不会哈夫曼树,他决定凭信仰出奇迹。
小D每次选数都是随机选两个数,随机规则为:
假如有三个数x,y,z,可能有相等的数,但是不影响选取。
小D会等概率选取(x,y)(x,z)(y,z)中的一对。
现在小D想知道他的程序的期望输出。
设期望输出为ans,为了避免精度误差,你只需要输出下述式子在模109 + 7域下的值。[ans \times \prod_{i=2}^{n}{\frac{i(i-1)}{2}}]
输入格式
从文件 huffman.in 中读入数据。
第一行一个正整数n。
第二行n个非负整数ai。
输出格式
输出到文件 huffman.out 中。
输出一个数表示答案。
样例
样例输入
5
1 2 2 3 3
样例输出
5082
数据范围与提示
【数据规模】
对于20的数据,n<=5。
对于另10的数据,数组a中最多只有5个正整数。
对于另10的数据,数组a中的数全部相同。
对于另30的数据,n<=103。
对于100的数据,2<=n<=105,0<=ai<=1000。
来源
NOI2016模拟赛 任之洲、洪华墩
可
知
答
案
要
求
的
仅
仅
是
所
有
方
案
的
总
和
。
。
可知答案要求的仅仅是所有方案的总和。。
可知答案要求的仅仅是所有方案的总和。。
且
无
论
a
[
i
]
=
?
在
最
后
答
案
中
系
数
都
一
样
。
且无论a[i]=?在最后答案中系数都一样。
且无论a[i]=?在最后答案中系数都一样。
设
f
[
i
]
为
i
个
数
时
的
系
数
设f[i]为i个数时的系数
设f[i]为i个数时的系数
设
i
个
数
时
总
的
合
并
的
方
案
数
c
n
t
=
3
×
2
×
4
×
3
×
.
.
.
×
(
i
−
2
)
×
(
i
−
1
)
设i个数时总的合并的方案数cnt=3\times2\times4\times3\times...\times(i-2)\times(i-1)
设i个数时总的合并的方案数cnt=3×2×4×3×...×(i−2)×(i−1)
先
上
柿
子
先上柿子
先上柿子
f
[
i
]
×
n
=
C
n
2
×
(
f
[
i
−
1
]
×
n
+
2
×
c
n
t
)
f[i]\times n=C_{n}^{2} \times(f[i-1]\times n+2\times cnt)
f[i]×n=Cn2×(f[i−1]×n+2×cnt)
直
观
理
解
就
是
对
于
i
个
数
时
的
答
案
,
视
为
i
个
1
时
,
可
以
枚
举
哪
两
个
数
被
选
。
每
个
选
取
方
式
第
一
步
贡
献
是
2
,
且
总
方
案
数
是
c
n
t
,
所
以
贡
献
时
2
×
c
n
t
。
后
i
−
2
步
由
f
[
i
−
1
]
推
得
,
贡
献
是
f
[
i
−
1
]
×
(
n
−
2
)
+
f
[
i
−
1
]
×
2
直观理解就是对于i个数时的答案,视为i个1时,可以枚举哪两个数被选。每个选取方式第一步贡献是2,且总方案数是cnt,所以贡献时2\times cnt。后i-2步由f[i-1]推得,贡献是f[i-1]\times(n-2)+f[i-1]\times 2
直观理解就是对于i个数时的答案,视为i个1时,可以枚举哪两个数被选。每个选取方式第一步贡献是2,且总方案数是cnt,所以贡献时2×cnt。后i−2步由f[i−1]推得,贡献是f[i−1]×(n−2)+f[i−1]×2
所
以
可
得
:
所以可得:
所以可得:
f
[
i
]
=
(
i
−
1
)
×
(
f
[
i
−
1
]
×
n
+
2
×
c
n
t
)
f[i]=(i-1)\times(f[i-1]\times n+2\times cnt)
f[i]=(i−1)×(f[i−1]×n+2×cnt)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 100005
using namespace std;
const long long mod=1000000007;
long long s,sum,iv2,f[N];
int n,a[N];
long long power(long long x,long long c){
long long now=1;
if(x==0)return 0;
while(c){
if(c&1)now=now*x%mod;
x=x*x%mod;c>>=1;
}
return now;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%lld",&a[i]),sum+=a[i];
iv2=power(2,mod-2);
//cout<<iv2<<endl;
f[1]=0;f[2]=1;s=1;
for(int i=3;i<=n;++i){
f[i]=(f[i-1]*i%mod+2*s)%mod*(i-1)%mod*iv2%mod;
s=1LL*i*(i-1)%mod*s%mod*iv2%mod;
}
sum%=mod;
printf("%lld\n",f[n]*sum%mod);
return 0;
}
/*
5
1 2 2 3 3
*/