【CSP】2023–05-3 解压缩 大模拟(没有特殊算法)

2023–05-3 解压缩 大模拟(没有特殊算法)

这题实际并不难,主要是要注意一些细节,比较考验你的编程习惯和逻辑是否清晰

思路就是按题目的来模拟

题目其实并不难理解,就是先算引导区、再算数据区的数据

遇到的问题(解题过程)

  1. 第一个遇到的问题就是输出没有搞对

每行8个字节16个字符换一次行

    for (int i = 0; i < allData.size(); i++)
    {
        if (i != 0 && i % 16 == 0)
        {
            cout << endl;
        }
        cout << allData[i];
    }

然后从0分变成了40分

在这里插入图片描述

  1. 没有想清楚pos的含义和字节的关系

就是这里应该对16取余但是对8取的余,并且重写了这块也就是对位运算转化为了十进制运算,逻辑更加清晰了,并且补充了对回溯引用的代码,然后就变成了60分,

            else if (t % 4 == 2)
            {
                l = t / 4 + 1;
                // 往后读取两个字节作为o
                o = hexToDec(string(temp[pos / 16].begin() + pos % 16, temp[pos / 16].begin() + pos % 16 + 2));
                pos += 2;
                o += hexToDec(string(temp[pos / 16].begin() + pos % 16, temp[pos / 16].begin() + pos % 16 + 2)) * 256;
                pos += 2;
            }

在这里插入图片描述

  1. 最坑的一个点就是对引导区长度计算的错误

本来是使用按位计算的

没有理清楚,并且不知道位运算的优先级是最低的(除去三元运算)详情请看c++运算优先级

用的是

if(num & 128 !=1)

这样不对这样num&128!=128才对

因为

1000 0000&1000 0000 = 1000 0000

只有第一位是1时4才是1000 0000 也就是128

然后使用了十进制这样更清晰一点

if(num<128)

然后就直接100分了

在这里插入图片描述

完整代码

#include <bits/stdc++.h>
using namespace std;
int s;
string temp[5000000];
int pos = 0;
string allData = "";
int hexToDec(string a) // 十六进制转十进制
{
    int num = 0;
    for (int i = 0; i < a.size(); i++)
    {
        int t;
        if (a[i] >= '0' && a[i] <= '9')
        {
            t = a[i] - '0';
        }
        else
            t = a[i] - 'a' + 10;
        num *= 16;
        num += t;
    }
    return num;
}
void addToData(int len) // 把压缩的数据插入到解压缩数据中
{
    len = len * 2;
    int end = pos + len;
    for (; pos < end; pos++)
    {
        allData.push_back(temp[pos / 16][pos % 16]);
    }
}
int main()
{
    cin >> s;
    getchar();
    int end = s / 8;
    if (s % 8 == 0)
        end--;
    for (int i = 0; i <= end; i++)
    {
        getline(cin, temp[i]);
    }
    int len = 0;
    int base = 1;
    for (int i = 0; i < 4; i++)
    {
        int num = hexToDec(string(temp[0].begin() + i * 2, temp[0].begin() + i * 2 + 2));
        len += base * (num % 128);
        base *= 128;
        pos += 2;
        if (num<128)
        {
            break;
        }
    }
    while (pos < s * 2)
    {
        // 字符串切片操作
        string type = string(temp[pos / 16].begin() + pos % 16, temp[pos / 16].begin() + pos % 16 + 2);
        pos += 2;
        int t = hexToDec(type);
        if (t % 4 == 3) // 不合法
        {
            break;
        }
        else if (t % 4 == 0) // 字面量
        {
            int length = t / 4;
            if (length < 60)
            {
                addToData(length + 1);
            }
            else
            {
                string l = "";
                for (int i = length - 59 - 1; i >= 0; i--)
                {
                    l.push_back(temp[(pos + i * 2) / 16][(pos + i * 2) % 16]);
                    l.push_back(temp[(pos + i * 2 + 1) / 16][(pos + i * 2 + 1) % 16]);
                }
                pos += (length - 59) * 2;
                length = hexToDec(l);  // 将十六进制字符串转化为十进制
                addToData(length + 1); // 插入到解压缩数据中
            }
        }
        else // 回溯索引
        {
            int o, l;
            if (t % 4 == 1)
            {
                // 高三位和后一个字节
                o = (t / 32) * 256 + hexToDec(string(temp[pos / 16].begin() + pos % 16, temp[pos / 16].begin() + pos % 16 + 2));
                pos += 2;
                l = (t / 4) % 8 + 4; // 中间三位 再加4
            }
            else if (t % 4 == 2)
            {
                l = t / 4 + 1;
                // 往后读取两个字节作为o
                o = hexToDec(string(temp[pos / 16].begin() + pos % 16, temp[pos / 16].begin() + pos % 16 + 2));
                pos += 2;
                o += hexToDec(string(temp[pos / 16].begin() + pos % 16, temp[pos / 16].begin() + pos % 16 + 2)) * 256;
                pos += 2;
            }
            // 得到o和l之后添加到解压缩数据中
            if (o >= l)
            {
                allData += string(allData.end() - o * 2, allData.end() - o * 2 + l * 2);
            }
            else if (o < l)
            {
                string t1 = string(allData.end() - o * 2, allData.end());
                for (int i = 0; i < l * 2; i++)
                {
                    allData.push_back(t1[i % t1.size()]);
                }
            }
        }
    }
    for (int i = 0; i < allData.size(); i++)
    {
        if (i != 0 && i % 16 == 0)
        {
            cout << endl;
        }
        cout << allData[i];
    }
    return 0;
}

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值