题目来源:

计算机软件能力认证考试系统

问题描述

试题编号: 202112-3
试题名称: 登机牌条码
时间限制: 1.0s
内存限制: 512.0MB
问题描述:

题目背景

西西艾弗岛景色优美,游人如织。但是,由于和外界的交通只能靠渡船,交通的不便严重制约了岛上旅游业的发展。西西艾弗岛管委会经过努力,争取到了一笔投资,建设了一个通用航空机场。在三年紧锣密鼓的主体建设后,西西艾弗岛通用航空机场终于开始进行航站楼内部软硬件系统的安装和调试工程了。小 C 是机场运营公司信息部的研发工程师,最近,信息部门的一项重要任务是,研发登机牌自助打印系统。如图所示的是设计部门根据国际民航组织的行业标准设计的登机牌样张。

登机牌上最重要的部分就是最下方的机读条形码了。小 C 承担了生成机读条形码算法的开发工作。从被编码的数据到条形码,中间有好多步骤要走。小 C 请你来帮忙,让你帮忙处理一下数据编码的问题。

题目描述

登机牌上的条形码,是 PDF417 码。PDF417 码的结构如下图所示。

PDF417 码组成的基本元素是码元(Module),所有的码元都是等大的矩形,填充有黑色或白色。码元先组成行,若干行堆叠组成整个 PDF417 码。每一行中,每 17 个码元表示一个码字(Code word)。码字是 PDF417 编码中的最小数据单位。每个码字图案中,有交替排列的四个黑色矩形和四个白色矩形,这便是 “417” 的由来。每行开始和结尾有固定的起始和中止图案。与他们相邻的是行左侧和右侧标志,表示行号、行内码字个数等信息。中间的是有效数据区。编码的步骤是:先按照编码规则,将被编码的数据转换为码字;接着根据选定 PDF417 码的宽度(即每行码字的数目)以及冗余程度计算校验码字;最后将码字按规则转换为对应的图案,并按照从左至右,从上至下的的顺序填入有效数据区,并与起始终止图案和行左右标志拼合,形成完整的 PDF417 码。

每个码字是一个 0 至 928 之间的数字,每个码字可以编码两个输入字符。对于输入的被编码的数据,按照下表进行编码。编码器共有三种模式:大写字母模式、小写字母模式和数字模式。在编码开始时,编码器处于大写字母模式。编码器处于某种模式时,仅能编码对应类型的字符,如果需要编码其它类型的字符,需要通过特殊值切换到对应模式下。要进行模式切换,可以有多种切换方法。例如,要从大写模式切入小写模式,可以直接用 27 切入,也可以先用 28 切入数字模式后立刻再用 27 切入小写模式。你需要选择最短的方式进行切换,因此只有前一种方法是正确的。需要注意的是,从小写模式不能直接切入大写模式,必须要经过数字模式过渡。

大写模式 小写模式 数字模式
0 A a 0
1 B b 1
2 C c 2
3 D d 3
4 E e 4
5 F f 5
6 G g 6
7 H h 7
8 I i 8
9 J j 9
10 K k
11 L l
12 M m
13 N n
14 O o
15 P p
16 Q q
17 R r
18 S s
19 T t
20 U u
21 V v
22 W w
23 X x
24 Y y
25 Z z
27 小写 小写
28 数字 数字 大写
29 填充 填充 填充

按照这个方法可以得到一系列的不超过 30 的数字。如果有奇数个这样的数字,则在最后补充一个 29,使之成为偶数个。将它们两两成组,假设 H 和 L 是一组中连续出现的两个数字,那么可以得到一个码字是:
30×H+L

例如,要编码 “HE1lo”,首先先根据字母表,产生数字序列:

H E    1    l  o
7 4 28 1 27 11 14

Data

由于只有奇数个数字,需要在末尾补充 29,然后将它们两两成组:

(7, 4), (28, 1), (27, 11), (14, 29)

Data

最后计算码字,例如:30×7+4=214,以此类推,可以得到码字为:

214, 841, 821, 449

Data

接下来要计算校验码。校验码字的数目,由校验级别确定。假设校验级别为 s(0≤s≤8),则校验码字的数目为 k=2s+1。特别地,如果指定了 s=−1,则表示不需要计算校验码字。要计算校验码字,首先要确定数据码字。数据码字由以下数据按顺序拼接而成(如图所示):

  • 一个长度码字,表示全部数据码字的个数 n,包括该长度码字、有效数据码字、填充码字;
  • 若干有效数据码字,是此前计算的码字序列;
  • 零个或多个由重复的 900 组成的填充码字,使得包括校验码字在内的码字总数恰能被有效数据区的行宽度整除。

设全部数据码字依次为 dn−1,dn−2,…,d0;校验码字依次为 ck−1,ck−2,…,c0。那么校验码字按照如下方式计算:

取 k 次多项式 g(x)=(x−3)(x−32)…(x−3k), (n−1) 次多项式 d(x)=dn−1xn−1+…dn−2xn−2+…d1x+d0,找到多项式 q(x) 和不超过 (k−1) 次的多项式 r(x),使得
xkd(x)≡q(x)g(x)−r(x)。那么多项式 r(x) 中 x 的 i 次项系数对 929 取模后(取正值)的数字即为校验码字 ci。

例如,如果要将 HE1lo 编码为 PDF417 条码,且有效数据区的行宽是 4 码字(即 68 码元),校验级别为 0。此时校验码字有两个。根据此前的编码结果,有效数据码字有 4 个。再加上一个长度码字,共有 7 个码字。因此需要补充一个填充码字,使包括校验码字在内的总码字数能够被 4 整除。这样,用于计算校验码字的数据码字有 6 个,分别是:

6, 214, 841, 821, 449, 900

Data

因此有 g(x)=x2−12x+27,d(x)=6x5+214x4+841x3+821x2+449x+900,不难得到 r(x)=−32902164x+98246277,因此相应可以计算出 c1=229≡−32902164mod929,c0=811≡98246277mod929。这样,全部码字序列即为:

6, 214, 841, 821, 449, 900, 229, 811

Data

在本题中,你需要帮助小 C 完成的任务是,给定被编码的数据,计算出需要填入有效数据区的码字序列。被处理的数据中只含有大写字母、小写字母和数字。

输入格式

从标准输入读入数据。

输入的第一行包含两个用空格分隔的整数 w、s,分别表示有效数据区每行能容纳的码字数和校验级别。保证 0<w<929,−1≤s≤8。特别地,当 s=−1 时,表示不需要计算校验码字。

输入的第二行是一个非空字符串,仅包含大小写字母和数字,长度保证编码后全部数据码字的个数少于 929。

输出格式

输出到标准输出。

输出若干行,每行一个数字,表示编码后的全部码字序列。

样例1输入

5 -1
HELLO

Data

样例1输出

5
214
341
449
900

Data

样例1解释

要求编码数据是 HELLO,首先查表将其对应成数字。注意,由于编码器在开始时就处于大写字母模式,因此不需要额外的模式切换。因此对应成的数字为:7, 4, 11, 11, 14。由于只有奇数个数字,因此补充 29,形成序列 7, 4, 11, 11, 14, 29。然后两两成组计算码字:7×30+4=214,以此类推,得到 214, 341, 449。本输入不要求产生校验码,且有效数据区的宽度是 5 码字。目前有效数据的码字是 3 个,加上开头要添加的长度码字,共有 4 个码字。因此,需要补充一个填充码字,使得总码字数达到 5 个,充满一行。注意,长度码字中的长度数据包括所有数据码字,因此长度码字是 5 而不是 4。最终可以得到码字序列 5, 214, 341, 449, 900

样例1输入

4 0
HE1lo

Data

样例1输出

6
214
841
821
449
900
229
811

Data

样例2解释

本组数据即为此前用于说明编码过程的示例。

子任务

对于 20% 的数据,有 s=−1,且输入字符串中仅含有大写字母或小写字母;

对于 40% 的数据,有 s=−1;

对于 80% 的数据,有 s≤2;

对于 100% 的数据,满足全部对于输入的要求。

解题思路:

本题前 40 分,认真模拟即可拿到分数。

后 60 分得分难点在于 如何求解 r(x), 即如何进行多项式求余 。

多项式求余思路我是看的这篇文章滴:

https://ccf-csp-project.github.io/CSP-Project-with-MkDocs/problem/24/3/1/#100

代码:

/* 100 */
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <math.h>
using namespace std;void char2num(string &s, vector<int> &a) {int preStatus = 0, curStatus;  // 0:A-Z; 1:a-z; 2:0-9map<int, char> myMap;myMap[0] = 'A';myMap[1] = 'a';myMap[2] = '0';for (char c: s) {if (c <= 'Z' && c >= 'A') {curStatus = 0;}else if (c <= 'z' && c >= 'a') {curStatus = 1;}else {curStatus = 2;}if (preStatus != curStatus) {if ((preStatus == 0 && curStatus == 1) || (preStatus == 2 && curStatus == 1)) {a.emplace_back(27);}else if ((preStatus == 1 && curStatus ==2) || (preStatus == 2 && curStatus == 0) || (preStatus == 1 && curStatus ==0) || (preStatus == 0 && curStatus ==2)) {a.emplace_back(28);}if (preStatus == 1 && curStatus == 0) {  // 转两次a.emplace_back(28);}}a.emplace_back(c - myMap[curStatus]);preStatus = curStatus;}if (a.size() % 2 != 0) {a.emplace_back(29);}
}void calculateG(int k, vector<int> &g) {g[0] = 1;int b = 3;for (int i = 1; i <= k; ++i) {for (int j = i; j > 0; --j) {g[j] = (g[j - 1] - (g[j] * b) % 929 + 929) % 929;}g[0] = (-1 * (g[0] * b) % 929 + 929) % 929;b = (3 * b) % 929;}/*cout<<"* "<<g.size()<<endl;for (int i = g.size() - 1; i >= 0; --i) {cout<<g[i]<<" ";}cout<<endl;*/
}void calculateR(int k, vector<int> xkd, vector<int> g, vector<int> &r) {/*cout<<"**XKD ";for (int i = xkd.size() - 1; i >= 0; --i) cout<<xkd[i]<<" "; cout<<endl;cout<<"**G ";for (int i = g.size() - 1; i >= 0; --i) cout<<g[i]<<" "; cout<<endl;*/// 多项式除余!for (int i = xkd.size() - 1; i >= k; --i) {if (xkd[i] == 0) {continue;}int a = xkd[i];for (int j = 0; j < g.size(); ++j) {xkd[i - j] = (xkd[i - j] - (a * g[g.size() - 1 - j]) % 929 + 929) % 929;}}for (int i = k - 1; i >= 0; --i) {//r[i] = ((-1 * xkd[i]) % 929 + 929) % 929;r[i] = (929 - xkd[i]) % 929;}
}void checkCode(int k,vector<int> b,vector<int> &r) {vector<int> g(k + 1, 0), xkd(b.size() + k, 0);// 计算g(x)calculateG(k, g);// 计算 x^k * d(x)for (int i = 0; i < b.size(); ++i) {xkd[k + b.size() - 1 - i] = b[i];}// 计算 r(x)  calculateR(k, xkd, g, r);
}int main(){int w, s;string str;cin>>w>>s;cin>>str;// 字符转码字vector<int> a;char2num(str, a);// 计算 30 * H + Lvector<int> b;b.emplace_back(0);  // 长度预记为 0for (int i = 0; i < a.size() / 2; ++i) {b.emplace_back(30 * a[2 * i] + a[2 * i + 1]);}// 填充int k = (s != -1? pow(2, s + 1) : 0);while ((k + b.size()) % w != 0) {b.emplace_back(900);}b[0] = b.size();// 计算校验码vector<int> cc(k, 0);if (s != -1) {checkCode(k, b, cc);}// 输出结果for (int i = 0; i < b.size(); ++i) {cout<<b[i]<<endl;}for (int i = k - 1; i >= 0 && s != -1; --i) {cout<<cc[i]<<endl;}return 0;
}

参考文章:

https://ccf-csp-project.github.io/CSP-Project-with-MkDocs/problem/24/3/1/#100

CSP CCF: 202112-3 登机牌条码 (C++)相关推荐

  1. CSP 202112-3 登机牌条码 40分

    2022.3.4 练习 CSP 202112-3 登机牌条码 之前在考场上只拿了20分,就是因为没仔细看题:在编码开始时,编码器处于大写字母模式,没有考虑这个情况...血泪啊 #include < ...

  2. CCF-CSP 202112-3 登机牌条码 100分

    原题链接:CCF-CSP 202112-3 登机牌条码 参考博客: CSP 202112-3 登机牌条码 CSP 202112-3 登机牌条码 (详细图解) #include <bits/std ...

  3. CCF-CSP 202112-3登机牌条码 解题思路+满分题解+详细注释

    CCF-CSP 202112-3登机牌条码 解题思路+满分题解+详细注释 题目链接:202112-3登机牌条码 思路: 第一步:按照题目顺序进行处理,即首先处理字符串,将对应的字符串转换成相应的数字编 ...

  4. 【CCF-CSP】202112-3 登机牌条码

    题目 202112-3 登机牌条码 代码 #include<bits/stdc++.h> using namespace std; const int N = 100010;int mai ...

  5. CSP202112-3登机牌条码

    目录 思路 模拟 输入模式处理 求长度码字,有效数据码字,填充码字 校验码字的求取 求gx(多项式乘法) 求x^n*dx 求校验码字 总结 原题太长就挂个链接CSP202112-3登机牌条码 思路 其 ...

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

    文章目录 问题描述 解题思路 数学基础 模拟思路 得分技巧 AC代码 问题描述 题目来源:CCF-CSP-202112-3:登机牌条码 解题思路 数学基础 需要一些很简单的数论基础知识(主要是同余的知 ...

  7. 登机牌条码(python)

    在ccfcsp官网(登机牌条码)的样例都能通过,但找半天没找到只有50分的原因. 主要的思路就是: 一.计算g(x)为了方便用的就是模拟人工计算. 二.计算长除法. 注释也很详细,希望有xd找到问题了 ...

  8. CSP登机牌条码202112-3

    改思路了,这题真难写,后半部分看不懂,所以我决定只过它的一二测试点,拿40分 #include <bits/stdc++.h> using namespace std;int main() ...

  9. CSP CCF: 201909-3 字符画) (C++)

    目录 题目来源 知识点 注意点 0分(略了) 20分 100分 代码挺长的,可以修改/删除一些地方(比如规划输出那一段中一长串字符的定义,可以从题目中就知道,就不用再转来转去了),优化一些地方(最后两 ...

最新文章

  1. 使用 PHPMailer 发送邮件
  2. yaml数组解析_yaml格式详解
  3. HTML中引入CSS的三种方式——响应式Web系列学习笔记
  4. 6.Excel项目排期表
  5. linux c之gdb常用断点调试总结
  6. 【CodeForces - 1084D】The Fair Nut and the Best Path (树形dp)
  7. 找不同颜色小游戏html源码,Javascript实现找不同色块的游戏
  8. 为什么要学习Python?怎么学?
  9. 云和恩墨大讲堂电子刊2019年4月刊发布
  10. sql server数据库的部署
  11. 【报告分享】2019年中国互联网企业战投发展白皮书.pdf(附154页pdf下载链接)...
  12. JavaScript学习(六十八)—表单校验案例
  13. 论文阅读:Uncertainty-aware Joint Salient Object and Camouflaged Object Detection
  14. mysql php 时间比较大小_MySql中时间比较的实现
  15. mac 谷歌浏览器不能登录账号不能同步
  16. STM32驱动模数转换芯片ADS1120(PT100铂电阻测温度)第2篇
  17. csf格式转换--逼自己一把
  18. vivos9桌面字体样式怎样修改
  19. 金融中需要的计算机知识,金融笔试中的综合知识一般会考什么?
  20. cc许可_免费的公共领域和CC0许可图片的16个来源

热门文章

  1. Java入门(3)—— 数组
  2. 算法分析与设计实验一
  3. android MediaPlayer架构
  4. 一维数组和二维数组矩阵乘法
  5. Java字节码文件和二进制文件的区别与联系
  6. DevOps功能实现解析
  7. python爬虫------王者荣耀英雄及技能爬取并保存信息到excel
  8. 征服嵌入式linux,成功征服英语的三十个好习惯
  9. 如何快速产生流量,流量精灵使用方法
  10. 字节测试爆料薪资普降17%,薪资和假期之间的抉择