题解【2.23考试T2】str

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 }

 

posted @ 2019-02-23 20:47  csxsi  阅读(214)  评论(0)    收藏  举报