题目链接
TUOJ
https://sim.csp.thusaac.com/contest/39/problem/2
反思
第39次认证其实是有点可惜的,可以说是有史以来离300最近的一次。为了拿200分花了一个半小时左右的时间,本来不需要这么久的(写出了bug),只留了两个多小时做第三题,思路分析正确,可惜没做完(没发现资料包里有题目给出的代码,手敲浪费了不少时间,实在是大冤种了)
9-21考完,出成绩那周一个下午就顺着思路把代码重新写了出来(要想留下考试时候只写了一半的代码,可以注释掉再提交,当时直接交编译失败,后面下载源代码,才这题的代码没存下来,难绷),但到11月才找到可以测试的地方,确实本可以拿下第三题。
当时就想着写一个题解,但想着只有20天就期中了结果拖到现在(昨天才考完),咱就是说能不能别这么拖沓啊喂
思路
1. 数据结构与初始化
数据存储
-
jtable:静态词条表(大小为S),初始化后固定不变 -
dtable:动态词条表(大小为D),可头部插入更新 -
每条词条是键值对
pair<string, string>
编码准备
-
初始化十六进制字符到4位二进制串的映射
mp -
读取哈夫曼树的前序遍历编码,重建哈夫曼树用于后续解码
2. 核心功能模块
哈夫曼树重建 (rebuildHuffmanTree)
-
输入:
"0"表示内部节点,"1"+字符表示叶节点 -
递归重建哈夫曼树,用于二进制串到原文的解码
解码函数 (decode)
-
根据重建的哈夫曼树,将二进制串逐位走树:
-
0→ 左子树,1→ 右子树 -
到达叶节点时输出字符,重置到根节点
-
输入预处理 (chuli)
处理三种输入格式:
-
普通字符串 (非
H开头):直接返回 -
双
H开头 :去掉第一个H返回 -
单
H开头:执行哈夫曼解码流程:-
去掉开头的
H -
将每个十六进制字符转为4位二进制
-
去掉末尾指定位数(由最后一位数字指定)
-
调用
decode哈夫曼解码
-
3. 三种操作模式 (solve)
操作1:查询
-
输入编号
n -
若
n ≤ S:从jtable取静态词条 -
否则:从
dtable取动态词条
操作2:查询并插入到动态表头部
-
类似操作1,但会将查询到的词条插入
dtable头部(LRU更新) -
若
n=0,则输入新键值对插入头部
操作3:仅查询
- 类似操作1,但不更新动态表
代码
cpp
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define pss pair<string,string>
vector<pss> jtable,dtable;
int S,D;
map<char,string>mp;
struct Node {
char data;
shared_ptr<Node> left;
shared_ptr<Node> right;
Node(char d) : data(d), left(nullptr), right(nullptr) {}
Node() : data('\0'), left(nullptr), right(nullptr) {}
};
shared_ptr<Node> root;
shared_ptr<Node> rebuildHuffmanTree(const string& s, int& index) {
if (index >= s.length()) return nullptr;
if (s[index] == '1') {
index++; // 跳过'1'
char ch = s[index++]; // 读取字符
return make_shared<Node>(ch);
} else if (s[index] == '0') {
index++; // 跳过'0'
auto node = make_shared<Node>();
node->left = rebuildHuffmanTree(s, index);
node->right = rebuildHuffmanTree(s, index);
return node;
}
return nullptr;
}
string decode(string s)
{
string ans="";
shared_ptr<Node> t=root; //temp
for(int i=0;i<s.size();i++)
{
if(s[i]=='0') t=t->left;
else t=t->right;
if(t->data!='\0') //根不是叶子,得在转移动之后判断
{
ans+=t->data;
t=root;
}
}
return ans;
}
string chuli(string s)
{
string ans="";
if(s[0]!='H') ans=s;
else if(s[0]=='H'&&s[1]=='H') ans=s.substr(1);
else{
s=s.substr(1);
string str;
for(int i=0;i<=s.size()-2-1;i++)
str+=mp[s[i]];
int n=s[s.size()-1]-'0';
str.erase(str.size()-n);
ans=decode(str);
}
return ans;
}
void solve()
{
int op; cin>>op;
if(op==1)
{
int n; cin>>n;
if(n<=S) cout<<jtable[n-1].first<<": "<<jtable[n-1].second<<endl; //1, ...S
else cout<<dtable[n-S-1].first<<": "<<dtable[n-S-1].second<<endl; //S+1, ...S+D
}
else if(op==2)
{
int n; cin>>n;
if(n!=0){
string v; cin>>v;
v=chuli(v);
if(n<=S)
{
cout<<jtable[n-1].first<<": "<<v<<endl; //1, ...S
dtable.insert(dtable.begin(),{jtable[n-1].first,v});
}
else {
cout<<dtable[n-S-1].first<<": "<<v<<endl;
dtable.insert(dtable.begin(),{dtable[n-S-1].first,v});
}
}
else{
string k,v; cin>>k>>v;
k=chuli(k), v=chuli(v);
cout<<k<<": "<<v<<endl;
dtable.insert(dtable.begin(),{k,v});
}
}
else if(op==3)
{
int n; cin>>n;
if(n!=0){
string v; cin>>v;
v=chuli(v);
if(n<=S) cout<<jtable[n-1].first<<": "<<v<<endl; //1, ...S
else cout<<dtable[n-S-1].first<<": "<<v<<endl;
}
else{
string k,v; cin>>k>>v;
k=chuli(k), v=chuli(v);
cout<<k<<": "<<v<<endl;
}
}
}
string transfer(int n)
{
string ans="";
while(n>0)
{
ans+=to_string(n%2); //warn:先取到的是最后一位
n/=2; //warn: / =2
}
reverse(ans.begin(),ans.end());
if(ans.size()<4) ans.insert(0,4-ans.size(),'0');
return ans;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
for(int i=0;i<=15;i++)
{
char c;
if(i<10) c=i+'0';
else c=i-10+'a'; //WARN:i-10
mp[c]=transfer(i);
// cout<<c<<endl;
// cout<<mp[c]<<endl;
}
// mp['0']="0000",mp['1']="0001",mp['2']="0010",mp['3']="0011";
// mp['4']="0100",mp['5']="0101",mp['6']="0110",mp['7']="0111";
// mp['8']="1000",mp['9']="1001",mp['a']="1010",mp['b']="1011";
// mp['c']="1100",mp['d']="1101",mp['e']="1110",mp['f']="1111";
cin>>S>>D;
for(int i=0;i<S;i++)
{
string s1,s2; cin>>s1>>s2;
jtable.push_back({s1,s2});
// cout<<jtable[i].first<<endl;
}
string encodedTree ; cin>>encodedTree ; //WARN:输入顺序错了
int idx = 0;
root = rebuildHuffmanTree(encodedTree, idx);
int n; cin>>n;
while(n--) solve();
return 0;
}
/*
4 5
3 4
-5 5
0 0
3 4
*/