CCF-CSP第39次认证第三题——HTTP 头信息(HPACK)【C++】

题目链接

TUOJhttps://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)

处理三种输入格式:

  1. 普通字符串 (非 H 开头):直接返回

  2. H 开头 :去掉第一个 H 返回

  3. 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

*/
点击并拖拽以移动
相关推荐
-To be number.wan21 小时前
C++ 赋值运算符重载:深拷贝 vs 浅拷贝的生死线!
前端·c++
疯狂的挖掘机21 小时前
记一次基于QT的图片操作处理优化思路(包括在图上放大缩小,截图,画线,取值等)
开发语言·数据库·qt
YGGP21 小时前
【Golang】LeetCode 64. 最小路径和
算法·leetcode
cnxy18821 小时前
围棋对弈Python程序开发完整指南:步骤4 - 提子逻辑和劫争规则实现
开发语言·python·机器学习
意趣新1 天前
C 语言源文件从编写完成到最终生成可执行文件的完整、详细过程
c语言·开发语言
李艺为1 天前
根据apk包名动态修改Android品牌与型号
android·开发语言
古城小栈1 天前
Rust变量设计核心:默认不可变与mut显式可变的深层逻辑
算法·rust
电商API&Tina1 天前
跨境电商 API 对接指南:亚马逊 + 速卖通接口调用全流程
大数据·服务器·数据库·python·算法·json·图搜索算法
XXYBMOOO1 天前
内核驱动开发与用户级驱动开发:深度对比与应用场景解析
linux·c++·驱动开发·嵌入式硬件·fpga开发·硬件工程
黄河滴滴1 天前
java系统变卡变慢的原因是什么?从oom的角度分析
java·开发语言