-
5 1 1 2 1 1 3 1 1 1 4 1 1 1 1 4 1 1 2 2
样例输出
-
1 2 12 24 24
描述
给定一个大小为n的字符集Σ中每个字符出现的频数,求不同的Huffman编码的数量模109 + 7。
一个编码是一个从Σ到01字符串的函数。 一个Huffman编码是一个由以下过程生成的编码:
初始时每个字符为一个集合。初始时所有字符对应到空字符串。一个集合S的频数w(S)定义为S内所有字符的频数的和。 不断进行以下操作直到只剩下一个集合:
选择两个不同的集合A和B使得w(A) + w(B)最小。将A内所有字符对应到的字符串前端加上'0'。将B内所有字符对应到的字符串前端加上'1'。添加一个集合C,为A和B的并。删除A和B。
两个编码不同当且仅当存在一个字符对应到的01字符串不同。
输入
第一行,T,测试点个数。下面T个测试点。
对于每个测试点,第一行,n,为字符集Σ的大小。 第二行,n个整数w1, ..., wn. 其中wi为第i个字符的频数。
1 ≤ n ≤ 106. 所有n的和 ≤ 106. 1 ≤ wi ≤ 106.
输出
T行。每行为对应测试点的答案。
首先统计相同频数出现的次数。这里用map来存储 map[频数]=频数出现次数。
然后从频数小的开始考虑。
1.如果最小频数的出现次数n是偶数。
则类似于考虑左右字数交换的情况下,n个不同元素进行划分,每块里面都只有2个元素的划分数。比如{1,2,3,4}的不考虑分块内的顺序划分有三种{(1,2),(3,4)},{(1,3),(2,4)},{(1,4),(2,3)},在考虑分块顺序的情况下应该是3*(2^3)。
依次考虑2个,4个,6个,8个不同元素不考虑顺序的划分,发现存在递推关系。
比如对于6个元素,先确定(1,2)的话,剩下的4个元素的划分实际上是4个不同元素的划分,然后再依次确定(1,3)、(1,4)、(1,5)、(1,6)的四个元素划分。所以6个元素的划分实际上为(6-1)*(4个不同元素不考虑顺序划分数)。
递推公式为
所以
再考虑每个划分内可以互换位置,则在这种情况下结果是
然后,把map[最小频数]擦除,map[最小频数*2]+=n/2
2.如果最小频数的出现次数n是奇数且大于1
则从里面里面挑出一个单独的,而其他两两组队的清楚共有C(n-1,n)=C(1,n)
此时参与配对的偶数个数可用上面的方法来求。
然后把map[最小频数*2]+=(n-1)/2,map[最小频数]赋值为1。
3.如果最小频数出现次数是1而且map的size为1就结束了。
4如果最小频数出现次数是1,map的size大于1
就要把改最小频数与第二小频数凑对。凑对共有map[第二小频数]种情况。
然后把map[最小频数+第二小频数]++,map[最小频数]擦除,map[第二小频数]--
源码
// 1111 Huffman编码.cpp : 定义控制台应用程序的入口点。
//
//递归算法
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <deque>
#include <map>
#include <algorithm>
using namespace std;
const int mode = 1000000007;
int same_num_count(int a) //a为偶数
{
int b = a - 1;
int res = 1;
while (b != 1)
{
res = b*res % mode;
b = b - 2;
}
return res;
}
vector<int> insert_new(vector<int> &w, int a)
{
if (w.size() != 0)
{
int flag = 1;
for (int i = 0; i < w.size(); i++)
{
if (w[i]>a)
{
flag = 1;
w.insert(w.begin() + i, a);
break;
}
if (w[i] < a)
flag = 0;
}
if (flag==0)
w.push_back(a);
}
else
w.push_back(a);
return w;
}
void comput(vector<int> &w, map<int, int>&count, int &ans)
{
if (count[w[0]] % 2 == 0)
{
ans = ans*same_num_count(count[w[0]]) % mode;
ans = ans*pow(2, count[w[0]] / 2);
ans = ans%mode;
int tmp = 2 * w[0];
if (count.find(tmp) == count.end())
{
count.insert(pair<int, int>(tmp, count[w[0]] / 2));
vector<int>::iterator iter = w.begin();
w.erase(iter);
w = insert_new(w, tmp);
}
else
{
count[tmp] += count[w[0]] / 2;
vector<int>::iterator iter = w.begin();
w.erase(iter);
}
//cout << ans << endl;
}
else if (count[w[0]] % 2 != 0 && count[w[0]] != 1)
{
ans = count[w[0]] * ans * same_num_count(count[w[0]] - 1) % mode;
ans = ans * pow(2, (count[w[0]] - 1) / 2);
ans = ans%mode;
int tmp = 2 * w[0];
if (count.find(tmp) == count.end())
{
count.insert(pair<int, int>(tmp, (count[w[0]] - 1) / 2));
w = insert_new(w, tmp);
}
else
count[tmp] += (count[w[0]] - 1) / 2;
count[w[0]] = 1;
//cout << ans << endl;
}
else
{
//cout << w.size() << endl;
ans = ans * 2 * count[w[1]];
ans = ans%mode;
count.erase(w[0]);
int tmp1 = w[0] + w[1];
//cout << tmp1 << endl;
vector<int>::iterator iter = w.begin();
w.erase(iter);
if (count[w[0]] == 1)
{
count.erase(w[0]);
iter = w.begin();
w.erase(iter);
}
else
count[w[0]]--;
if (count.find(tmp1) == count.end())
{
count.insert(pair<int, int>(tmp1, 1));
w = insert_new(w, tmp1);
}
else
count[tmp1]++;
//cout << w.size() << endl;
//cout << ans << endl;
}
}
int main()
{
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
vector<int>w;
map<int, int>count;
for (int i = 1; i <= n; i++)
{
int a;
cin >> a;
if (count.find(a) == count.end() || count.size() == 0)
{
count.insert(pair<int, int>(a, 1));
w.push_back(a);
}
else
count[a]++;
}
sort(w.begin(), w.end());
int ans = 1;
while (w.size() > 1 || (w.size() == 1 && count[w[0]] != 1))
comput(w, count, ans);
if (w.size() == 1 && count[w[0]] != 1)
ans *= 2;
cout << ans << endl;
}
system("pause");
return 0;
}
竟然超时了
再改了一下终于过了(scanf和printf有时还蛮有用的)
#include <iostream>
#include <vector>
#include <map>
#include <cstdio>
using namespace std;
const int mode = 1000000007;
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n;
scanf("%d", &n);
map<long long, int>count;
int a;
for (int i = 1; i <= n; i++)
{
scanf("%d", &a);
count[a]++;
}
long long int ans = 1;
while (1)
{
map<long long, int>::iterator iter = count.begin();
if (iter->second % 2 == 0)
{
long long tmp1 = iter->second;
while (tmp1)
{
ans = ans*(tmp1 - 1) * 2 % mode;
tmp1 = tmp1 - 2;
}
long long tmp2 = 2 * iter->first;
count[tmp2] += iter->second / 2;
count.erase(iter);
}
else if (iter->second % 2 != 0 && iter->second != 1)
{
ans = iter->second * ans % mode;
int tmp3 = iter->second - 1;
while (tmp3)
{
ans = ans*(tmp3 - 1) * 2 % mode;
tmp3 = tmp3 - 2;
}
long long tmp = 2 * iter->first;
count[tmp] += (iter->second - 1) / 2;
iter->second = 1;
}
else
{
if (count.size() == 1)
break;
long long t = iter->first;
count.erase(iter);
iter = count.begin();
ans = ans * 2 * iter->second%mode;
long long tmp1 = t + iter->first;
count[tmp1]++;
iter->second--;
if (iter->second == 0)
count.erase(iter);
}
}
printf("%d\n", int(ans));
}
system("pause");
return 0;
}
(づ ̄ 3 ̄)づ