BZOJ NOI 十连测 哈夫曼树

Posted 殇雪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ NOI 十连测 哈夫曼树相关的知识,希望对你有一定的参考价值。

【问题描述】
有这样一个经典问题:
? 给出一个长度为??的非负整数数组??。
? 每次可以选择数组中两个不同位置的数????, ????(?? ?= ??),将它们删除,然
后再向数组中加入一个新的元素,值为???? + ????。
? 这样一次操作产生的代价是这个新元素的值,即???? + ????。
? 例如当前数组中的数为?? = {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;
}

 

以上是关于BZOJ NOI 十连测 哈夫曼树的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ NOI十连测 第一测 T1

BZOJ NOI十连测 第一测 T2

[Noi2016十连测第三场]线段树

Noi 十连测 基因改造计划

NOI十连测 第五测 T2

Noi2016十连测第二场-黑暗 (二项式定理/斯特林数+CDQ+NTT)