【问题描述】
有这样一个经典问题:
? 给出一个长度为??的非负整数数组??。
? 每次可以选择数组中两个不同位置的数????, ????(?? ?= ??),将它们删除,然
后再向数组中加入一个新的元素,值为???? + ????。
? 这样一次操作产生的代价是这个新元素的值,即???? + ????。
? 例如当前数组中的数为?? = {1, 1, 3, 1},选择??1 = 1, ??4 = 1进行操作
后,数组变为{1, 3, 2},代价为2。
? 一共会进行?? − 1次操作,要求最小化代价之和。
这道题可以用经典的哈夫曼树算法解决,然而小??正在??????考场上,
根本不会哈夫曼树,他决定凭信仰出奇迹。
小??每次选数都是随机选两个数,随机规则为:
? 假如有三个数??, ??, ??,可能有相等的数,但是不影响选取。
? 小??会等概率选取(??, ??)(??, ??)(??, ??)中的一对。
现在小??想知道他的程序的期望输出。
设期望输出为??????,为了避免精度误差,你只需要输出下述式子在
模109 + 7域下的值。
?????? ×
?? Π???=2
??(?? − 1)
【数据规模】
对于20%的数据,?? ≤ 5。
对于另10%的数据,数组??中最多只有5个正整数。
对于另10%的数据,数组??中的数全部相同。
对于另30%的数据,?? ≤ 103。
SOL:我们发现 ans=sigma ai* 一个系数。
我们又发现答案要求的是所有方案的和。
我们不难发现这个系数是关于n的函数。
我们构造一个有n-2个1,一个2的序列。
我们知道n个1通过一步后必然会成上一次的结果。
那么我们可以对n个1的情况构造等式:
f[n]*n(n个1的答案)=(f[n-1]*n(n-2个1,一个2的答案)+2(合并1次的代价)*S当前方案数)*2Cn(在n个中选2个方案数)
我们不难发现S当前方案数=前n-2个三角型数的积。
所以·O(N)跑一趟就好了。
#include<bits/stdc++.h> #define mo 1000000007 #define iv2 500000004 using namespace std; int n,p; long long f[1000007],s,sum; signed main () { freopen("huffman.in","r",stdin); freopen("huffman.out","w",stdout); scanf("%d",&n); f[1]=0; f[2]=1; s=1; for (int i=3;i<=n;i++) { f[i]=(f[i-1]*i%mo+2*s)%mo*(i-1)%mo*iv2%mo; s=s*i%mo*(i-1)%mo*iv2%mo; } // cout<<f[n]; for (int i=1;i<=n;i++) scanf("%d",&p),sum+=p; sum%=mo; printf("%lld\n",sum*f[n]%mo); return 0; // cout<<(7830*7+2*1*3*6*10*15)*6/2; }