2016青岛网络赛G HDU - 5884 (k叉哈夫曼树)

image

  • 容易想到二分
  • check时若用优先队列,check的时间复杂度是nlognlogn的,
  • k叉哈夫曼树优化掉一个logn:
    先补r个0 :int r = (k - 1) - (n - 1) % (k - 1);
    (每次减k-1,一直减到剩1个)
    初始元素从小到大地入队q1,q1和q2队头取最小的k个元素,入队q2,一直到q2只剩一个元素为止
    这样合并能保证先合并最小的k个元素,那么q2队头的k个元素合并一定比队尾的元素大,因为队尾的元素的子元素是先合并的,它们比后来要合并的队头k个元素小。 先补r个0才能满足每次都取k个。
    具体原理不懂

k叉哈夫曼模板:

ll check( int x ) {
   queue<ll> q1, q2;
   int r = ((x - 1) - (n - 1) % (x - 1)) % (x - 1);
   while( r -- ) q1.push(0);
   for ( int i = 1; i <= n; ++ i ) q1.push(a[i]);
   bool f = 0; ll sum = 0, res = 0; int cnt = 0;
   while( 1 ) {
       //取元素
       if( q1.size() && q2.size() ) {
           if( q1.front() > q2.front() ) {
               sum += q2.front(); q2.pop(); 
           } else {
               sum += q1.front(); q1.pop();
           }
       } else if( q1.size() ) {
           sum += q1.front(); q1.pop();
       } else if( q2.size() ) {
           sum += q2.front(); q2.pop();
       } 
       //合并完了
       if( q1.size() == 0 && q2.size() == 0 ) return res + sum;
       //合并满k个了
       if( ++ cnt == x ) {
           q2.push(sum);
           res += sum; sum = 0, cnt = 0;
       }
       
   }

}
posted @ 2022-07-08 11:06  qingyanng  阅读(41)  评论(0编辑  收藏  举报