给定一个大小为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行。每行为对应测试点的答案。
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
首先统计相同频数出现的次数。这里用map来存储 map[频数]=频数出现次数。
然后从频数小的开始考虑。
则类似于考虑左右字数交换的情况下,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
则从里面里面挑出一个单独的,而其他两两组队的清楚共有C(n-1,n)=C(1,n)
此时参与配对的偶数个数可用上面的方法来求。
然后把map[最小频数*2]+=(n-1)/2,map[最小频数]赋值为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 ̄)づ
原文地址:http://blog.csdn.net/youb11/article/details/45828479