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

*/
点击并拖拽以移动
相关推荐
Data_agent9 小时前
1688按图搜索1688商品(拍立淘)API ,Python请求示例
爬虫·python·算法·图搜索算法
汉克老师9 小时前
2023年海淀区中小学信息学竞赛复赛(小学组试题第二题 回文时间 (time))
c++·算法·北京海淀中小学信息竞赛·模拟法
沐风。569 小时前
Object方法
开发语言·前端·javascript
IT_阿水9 小时前
C语言之printf函数用法
c语言·开发语言·printf
代码雕刻家9 小时前
1.9.课设实验-数据结构-图-校园跑最短路径
c语言·数据结构·算法·图论
laocooon5238578869 小时前
C语言,少了&为什么报 SegmentationFault
c语言·开发语言
white-persist9 小时前
【攻防世界】reverse | re1-100 详细题解 WP
c语言·开发语言·网络·汇编·python·算法·网络安全
CHANG_THE_WORLD9 小时前
Python 中的循环结构详解
开发语言·python·c#
程序员-周李斌9 小时前
ConcurrentHashMap 源码分析
java·开发语言·哈希算法·散列表·开源软件