JZOJsenior1776 經濟編碼

2021-08-07 03:46:45 字數 4030 閱讀 2160

description

為降低資料儲存的空間或增加資料傳送的速度,編碼是常用的方法。

假設有乙個字符集,每個字元出現的頻率是已知的。現在要把每個字元編碼成為乙個二元字串(例如把「a」編碼作101),採用的編碼必須合乎以下條件:乙個字元的編碼不可以是另乙個字元的前置(prefix)。前置的定義如下:若乙個字串s1為另乙個字串s2的前置,則從s2的最後乙個字元開始,連續刪除一定數量的字元後可以得到s1(s2本身也是s2的前置),舉例而言:如果字元「a」的編碼是101,而字元「b」的編碼為01,則「b」的編碼不為「a」編碼的前置;如果字元「c」的編碼為1100,而字元「d」的是11,則「d」的編碼是「c」編碼的前置。以下的編碼方式可以在符合這個條件下給出最經濟的編碼,請找出使用下述方法做最經濟編碼時,乙個字元編碼的預期長度。

編碼法:

1、 如以下所述建立一棵二元樹。

先從字符集選取兩個出現頻率最低的字元作合併,合併後以乙個全新的虛擬字元取代這兩個字元,新字元的頻率等於這兩個舊字元頻率的總和,並令這兩個舊字元為此新字元的兩個子樹,左右不限。重複以上操作,直至字符集剩下乙個字元為止。如下圖(i)到(iv)。

2、 再依照以下所述方法將各字元作編碼。

由上一步驟所得之二元樹,將每個內部節點(internal node)連往左子樹的邊(edge)標記為「0」,連往右子樹的邊標記為「1」,如下圖(v)所示。一字元的編碼即為從樹根(root)至此字元,經過的每乙個邊的標記所成之字串。在此「a」編碼作000,「?」編碼作01。

在按照上述的編碼法完成最經濟編碼之後,就可以計算這個字元編碼的預期長度。首先算出每個字元的預期長度=編碼長度×出現頻率,然後把所有字元的預期長度結合起來,就可以得到此字元編碼的預期長度。下表是上述編碼的計算範例。

字元 編碼 編碼長度 出現頻率 預期長度

a 000 3 0.1 0.3

b 001 3 0.1 0.3

? 01 2 0.3 0.6

8 1 1 0.5 0.5

字元編碼的預期長度 1.7

input

第一行為兩整數n和m,分別代表字符集的大小和文章總長度。然後每乙個字元分行列出,每行列出一字元出現的次數。

output

預期乙個字元編碼的長度,保留至小數點後6位。

sample input

輸入範例1:

4 10

1 1 3 5

輸出範例1:

1.700000

輸入範例2:

6 100

30 30

5 25 5 5

輸出範例2:

2.250000

sample output

data constraint

hint

【資料約定】

對於50%的資料,1<=n<=2000;

對於100%的資料,1<=n<=200000。

所有字元出現次數和等於文章總長度。

【提示】

思路:

這題除了題面比較長,其實沒有過多的技術含量吧……

我來簡化下題意:

從乙個序列裡面選出最小值和次小值,把兩個數的和重新塞回序列裡,直到序列剩下乙個數。其實就是一道裸的合併果子嘛(雖說我沒有做合併果子——)

(說的好聽一點,建出來的那棵樹,叫哈夫曼樹)

用堆維護一下序列最小值,每次取出最小和次小

注意每次合併兩個數時,新開乙個點,把左兒子、右兒子和兩個數的和記錄一下,把這個點塞回堆裡去

最後全部弄完以後,dfs遍歷一次,求出∑深度×節點值

**:

var

heap,tree:array[0..1000000,0..2]of longint;

n,m,i,j,x,y,xx,yy,tot:longint;

ans:extended;

procedure

swap

(var x,y:longint);

var z:longint;

begin

z:=x;

x:=y;

y:=z;

end;

procedure

up(x:longint);

var y:longint;

begin

if n=1

then

exit;

while x>1

dobegin

y:=x div

2; if heap[y,0]>heap[x,0] then

begin

swap(heap[x,0],heap[y,0]);

swap(heap[x,1],heap[y,1]);

end;

x:=y;

end;

end;

procedure

down

(x:longint);

var y:longint;

begin

while x<=n div2do

begin

y:=2*x;

if (yand(heap[y,0]>heap[y+1,0])then inc(y);

if heap[x,0]>heap[y,0] then

begin

swap(heap[x,0],heap[y,0]);

swap(heap[x,1],heap[y,1]);

end;

x:=y;

end;

end;

procedure

dfs(x,v:longint);

begin

if (tree[x,1]=0)and(tree[x,2]=0)then

begin

ans:=ans+v*(tree[x,0]/tot);

exit;

end;

if tree[x,1]<>0

then dfs(tree[x,1],v+1);

if tree[x,2]<>0

then dfs(tree[x,2],v+1);

end;

begin

readln(n,tot);

for i:=1

to n do

begin

read(heap[i,0]);

heap[i,1]:=i;

tree[i,0]:=heap[i,0];

end;

for i:=n div

2downto

1do down(i);

m:=n;

while n>1

dobegin

x:=heap[1,0];

xx:=heap[1,1];

heap[1,0]:=heap[n,0];

heap[1,1]:=heap[n,1];

heap[n,0]:=0;

heap[n,1]:=0;

dec(n);

down(1);

y:=heap[1,0];

yy:=heap[1,1];

heap[1,0]:=heap[n,0];

heap[1,1]:=heap[n,1];

heap[n,0]:=0;

heap[n,1]:=0;

dec(n);

down(1);

inc(n);

inc(m);

heap[n,0]:=x+y;

heap[n,1]:=m;

up(n);

tree[m,0]:=x+y;

tree[m,1]:=xx;

tree[m,2]:=yy;

end;

dfs(m,0);

writeln(ans:0:6);

end.

177 單詞替換

題目描述 你需要輸出替換之後的句子。示例 1 輸入 dict 詞典 cat bat rat sentence 句子 the cattle was rattled by the battery 輸出 the cat was rat by the bat 注 輸入只包含小寫字母。1 字典單詞數 1000...

jzoj senior 1273 袁紹的刁難

1273.袁紹的刁難 recruitment.pas cpp file io input recruitment.in output recruitment.out time limits 1000 ms memory limits 131072 kb description 黃巾之亂後,郭嘉到了袁...

careercup 中等難度 17 7

17.7 給定乙個整數,列印該整數的英文描述 例如 one thousand,two hundred thirty four 解法 舉個例子,在轉換19 323 984時,我們可以考慮分段處理,沒三位轉換一次,並在適當的地方插入 thousand 千 和 million 百萬 也即,convert ...