CCF-CSP-202112-3:登机牌条码(C++11题解)

问题描述

解题思路

数学基础

    需要一些很简单的数论基础知识(主要是同余的知识),参考数论基础(oi-wiki)

模拟思路

    将整个计算登机牌条码的完整过程拆分成以下步骤:

  • 对字符进行编码:PDF417::PDF417Encoder::Encoder::EncodeCharacters()
  • 对编码后的值进行填充:PDF417::PDF417Encoder::Encoder::PadEncodedValue()
  • 将编码并填充后的值转换成码字:PDF417::PDF417Encoder::Encoder::CalcCodeWord()
  • 对码字进行填充:PDF417::PDF417Encoder::Encoder::PadCodeWord()
  • 计算校验码:PDF417::PDF417Encoder::Encoder::CalcCheckSum()

这一步骤涉及一些简单的多项式乘法、多项式除法以及同余的知识。

  • 打印结果:PDF417::PDF417Encoder::Encoder::Print()

得分技巧

    计算校验和的过程相对来其他过程来说了一点。在无法完成这一步骤的情况下,只完成其他步骤也能轻松拿40分。

AC代码

提交结果

后面几条提交PA是因为没有及时取模,导致整数溢出了。

关于编码风格的说明:习惯性地使用了一些面向对象的思想对代码进行封装。实际考试时考虑到编码效率,可能没必要这么做。

#include <iostream>
#include <string>
#include <vector>
#include <deque>
#include <cmath>

namespace PDF417
{
    class PDF417Encoder
    {
    private:
        class Encoder
        {
        private:
            enum class EncoderStatus
            {
                Uppercase, Lowercase, Number
            };

            using EncodedValueType = char;
            using CodeWordType = short;

        public:
            Encoder(size_t LineCapacity, int ChecksumLevel, std::string DataToBeEncoded)
                : m_EncoderStatus(EncoderStatus::Uppercase),
                  m_LineCapacity(LineCapacity), m_ChecksumNum(ChecksumLevel == -1 ? 0 : (1 << (ChecksumLevel + 1))), m_DataToBeEncoded(DataToBeEncoded)
            { }

        public:
            void Encode()
            {
                EncodeCharacters();

                PadEncodedValue();

                CalcCodeWord();

                PadCodeWord();

                CalcCheckSum();

                Print();
            }

        private :
            inline std::pair<EncoderStatus, EncodedValueType> EncodeCharacter(const char &Character)
            {
                if(Character >= 'a' && Character <= 'z') return std::make_pair<EncoderStatus, EncodedValueType>(EncoderStatus::Lowercase, Character - 'a');
                if(Character >= 'A' && Character <= 'Z') return std::make_pair<EncoderStatus, EncodedValueType>(EncoderStatus::Uppercase, Character - 'A');
                
                // if(Character >= '0' && Character <= '9') 
                return std::make_pair<EncoderStatus, EncodedValueType>(EncoderStatus::Number, Character - '0');
            }

            void TransformEncoderStatusTo(const EncoderStatus &EncoderStatusTo)
            {
                if(m_EncoderStatus == EncoderStatusTo) return;

                do
                {
                    // Transform To Lowercase
                    if(EncoderStatusTo == EncoderStatus::Lowercase)
                    {
                        m_EncodedValueVector.emplace_back(27);
                        break;
                    }

                    // Transform To Number
                    if(EncoderStatusTo == EncoderStatus::Number)
                    {
                        m_EncodedValueVector.emplace_back(28);
                        break;
                    }

                    // Transform To Uppercase
                    if(EncoderStatusTo == EncoderStatus::Uppercase)
                    {
                        // Transform Number To Uppercase
                        if(m_EncoderStatus == EncoderStatus::Number)
                        {
                            m_EncodedValueVector.emplace_back(28);
                            break;
                        }

                        // Transform Lowercase To Uppercase
                        m_EncodedValueVector.emplace_back(28);
                        m_EncodedValueVector.emplace_back(28);
                        break;
                    }
                }
                while(false);

                m_EncoderStatus = EncoderStatusTo;
            }

        private:
            void EncodeCharacters()
            {
                for(const char &Character : m_DataToBeEncoded)
                {
                    std::pair<EncoderStatus, EncodedValueType> EncodedResult = EncodeCharacter(Character);

                    EncoderStatus EncoderStatusTo = EncodedResult.first;

                    TransformEncoderStatusTo(EncoderStatusTo);

                    m_EncodedValueVector.emplace_back(EncodedResult.second);
                }
            }

            void PadEncodedValue()
            {
                int DataLength = m_EncodedValueVector.size();
                if(DataLength & 1) m_EncodedValueVector.emplace_back(29);
            }

            void CalcCodeWord()
            {
                int EncodedValueNum = m_EncodedValueVector.size();

                for(int i = 0; i < EncodedValueNum; i += 2)
                {
                    m_CodeWordDeque.emplace_back(m_EncodedValueVector[i] * 30 + m_EncodedValueVector[i + 1]);
                }
            }

            void PadCodeWord()
            {
                int DataCodeWordNum = m_CodeWordDeque.size();

                int CodeWordNumRemainder = (m_ChecksumNum + DataCodeWordNum + 1) % m_LineCapacity;
                int PaddingTimes = CodeWordNumRemainder ? m_LineCapacity - CodeWordNumRemainder : 0;

                for(int i = 0; i < PaddingTimes; ++i)
                {
                    m_CodeWordDeque.emplace_back(900);
                }

                m_CodeWordDeque.emplace_front(DataCodeWordNum + 1 + PaddingTimes);
            }

            void CalcCheckSum()
            {
                if(m_ChecksumNum == 0) return;

                // g(x) = (x - 3)(x - 9)(x - 27)······
                std::deque<int> Polynomial_gx({1, -3});
                int TempNumber = -3;

                for(int i = 1; i < m_ChecksumNum; ++i)
                {
                    TempNumber *= 3;
                    TempNumber %= 929;

                    int n = Polynomial_gx.size();
                    Polynomial_gx.emplace_back(0);

                    for(int j = n; j >= 1; --j)
                    {
                        Polynomial_gx[j] += Polynomial_gx[j - 1] * TempNumber;
                        Polynomial_gx[j] %= 929;
                    }
                }

                // d(x) = d_(n-1) * x ^ (n - 1) + ·····
                std::deque<int> Polynomial_dx;
                for(const int &Coefficient : m_CodeWordDeque)
                {
                    Polynomial_dx.emplace_back(Coefficient);
                }

                // f(x) = d(x) * x ^ k
                std::deque<int> Polynomial_fx = std::move(Polynomial_dx);
                for(int i = 0; i < m_ChecksumNum; ++i)
                {
                    Polynomial_fx.emplace_back(0);
                }

                while(Polynomial_fx.size() >= Polynomial_gx.size())
                {
                    int Quotient = Polynomial_fx.front();

                    for(int i = 0, n = Polynomial_gx.size(); i < n; ++i)
                    {
                        Polynomial_fx[i] -= Polynomial_gx[i] * Quotient;
                        Polynomial_fx[i] %= 929;
                    }

                    if(Polynomial_fx.front() == 0) Polynomial_fx.pop_front();
                }

                //
                for(int &Coefficient : Polynomial_fx)
                {
                    Coefficient = - Coefficient;
                    Coefficient %= 929;
                    if(Coefficient < 0) Coefficient += 929;
                    m_CodeWordDeque.emplace_back(Coefficient);
                }
            }

            void Print()
            {
                for(const CodeWordType &CodeWord_i : m_CodeWordDeque)
                {
                    std::cout << CodeWord_i << std::endl;
                }
            }

        private:
            EncoderStatus m_EncoderStatus;
            std::vector<EncodedValueType> m_EncodedValueVector;
            std::deque<CodeWordType> m_CodeWordDeque;

            size_t m_LineCapacity;
            int m_ChecksumNum;
            std::string m_DataToBeEncoded;
        };

    public:
        PDF417Encoder() = default;

        void Encode(size_t LineCapacity, int ChecksumLevel, std::string DataToBeEncoded)
        {
            Encoder EncoderEntity(LineCapacity, ChecksumLevel, std::move(DataToBeEncoded));
            EncoderEntity.Encode();
        }
    };
}


int main()
{
    // IO initialization
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    // input line capacity and checksum level
    size_t LineCapacity;
    int ChecksumLevel;

    std::cin >> LineCapacity >> ChecksumLevel;

    // input data that needs to be encoded
    std::string DataToBeEncoded;
    std::cin >> DataToBeEncoded;

    // Encode
    PDF417::PDF417Encoder EncoderEntity;
    EncoderEntity.Encode(LineCapacity, ChecksumLevel, std::move(DataToBeEncoded));

    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值