1. 程式人生 > >題解【2.23考試T2】str

題解【2.23考試T2】str

時間 組合數 stdin return 由於 最小化 前綴 而且 bits

2. str
【題目描述】
  這是一道傳統題,源代碼的文件名為 str.cpp/c/pas。
  構造 n 個 01 字符串 S1...Sn,使得對於任意 i≠j,Si 不是 Sj 的前綴。在最小化串長和的前提下,求方案數,模 1,000,000,007。
【輸入格式】
  從 str.in 中讀入。
  僅一行,一個不小於 2 的正整數 n。
【輸出格式】
  輸出到 str.out 中。
  僅一行,一個非負整數,表示方案數對 1,000,000,007 取模後的結果。
【輸入樣例 A】
3
【輸出樣例 A】
12
【輸入樣例 B】
233
【輸出樣例 B】
433982621
【評分標準】
對於 30%的數據,n<=10;
對於 60%的數據,n<=2,000;

對於 80%的數據,n<=100,000;
對於 100%的數據,n<=10,000,000。
時間限制 1s,空間限制 512MB。

題解:

  關於這道題,怎麽也想不到正解竟然是哈夫曼樹……

  考慮特殊的哈夫曼樹,一定只有 d 和 d+1 兩種深度(其中 d 是使得2?? ≤ ??的最大整數),並且是在 d 深度的滿樹的基礎上,選擇一些葉子擴展出叉。

  於是要計算一下組合數,而且註意到由於最後哈夫曼樹的每個葉子和每個串的對應關系是任意的,所以還要計算一下階乘。

  代碼(std):

 1 #include <bits/stdc++.h>
 2
#define rep(i,l,r) for(int i=l;i<=r;i++) 3 #define per(i,r,l) for(int i=r;i>=l;i--) 4 #define mo 1000000007 5 #define N 10000005 6 int inv(int x) 7 { 8 int y=mo-2,s=1; 9 while(y) 10 { 11 if(y&1) s=1ll*s*x%mo; 12 y>>=1; 13 x=1ll*x*x%mo; 14 }
15 return s; 16 } 17 int n,a,fac[N]; 18 int main() 19 { 20 char fni[]="str.in",fno[]="str.out"; 21 freopen(fni,"r",stdin); 22 freopen(fno,"w",stdout); 23 scanf("%d",&n); 24 fac[0]=1; 25 rep(i,1,n) fac[i]=1ll*fac[i-1]*i%mo; 26 a=1; 27 while(a<<1<=n) a<<=1; 28 printf("%d\n",1ll*fac[n]*fac[a]%mo*inv(fac[n-a])%mo*inv(fac[a*2-n])%mo); 29 fclose(stdin); 30 fclose(stdout); 31 }

題解【2.23考試T2】str