题目背景

西西艾弗岛景色优美,游人如织。但是,由于和外界的交通只能靠渡船,交通的不便严重制约了岛上旅游业的发展。西西艾弗岛管委会经过努力,争取到了一笔投资,建设了一个通用航空机场。在三年紧锣密鼓的主体建设后,西西艾弗岛通用航空机场终于开始进行航站楼内部软硬件系统的安装和调试工程了。小 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

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

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

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

214, 841, 821, 449

接下来要计算校验码。校验码字的数目,由校验级别确定。假设校验级别为 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

因此有 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

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

输入格式

从标准输入读入数据。

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

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

输出格式

输出到标准输出。

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

样例1输入

5 -1
HELLO

样例1输出

5
214
341
449
900

样例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

样例1输出

6
214
841
821
449
900
229
811

样例2解释

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

子任务

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

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

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

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

AC代码:

#include<iostream>
#include<math.h>
using namespace std;
int flag=0;//0为大写,1为小写,-1为数字,初始为大写
int list[2001]={0};//记录编码数字
void func_arg(char ch, int &h)//把字符转成编码数字,并记录在list中
{if(ch>='A'&&ch<='Z'){if(flag==0)list[h++]=ch-'A';else if(flag==1){list[h++]=28;list[h++]=28;list[h++]=ch-'A';flag=0;}else if(flag==-1){list[h++]=28;list[h++]=ch-'A';flag=0;}}else if(ch>='a'&&ch<='z'){if(flag==1)list[h++]=ch-'a';else {list[h++]=27;list[h++]=ch-'a';flag=1;}}else if(ch>='0'&&ch<='9'){if(flag==-1)list[h++]=ch-'0';else {list[h++]=28;list[h++]=ch-'0';flag=-1;}}
}
int main()
{int w=0, s=0;scanf("%d%d", &w, &s);char ch;scanf("%c", &ch);//吸收换行符 int h=1;//把编码数字放入数组list的位置h中 scanf("%c", &ch);while(ch!='\n'){func_arg(ch, h);scanf("%c", &ch);}if(h%2==0)list[h]=29;//如果数字不为偶数个,则补29(h是指向数组的下一个空位置)else h--;int n=0, supply=0;    if(s==-1)n=1+(h/2);else n=1+(h/2)+pow(2, s+1);for(int i=1; ;i++){if(w*i>=n){supply=w*i-n;//填充码字的个数n=1+(h/2)+supply;//长度码字break;}}int d[2001]={0};d[0]=n;//长度码字 for(int i=1; i<=(h/2); i++)//有效数据码字 {d[i]=list[2*i-1]*30+list[2*i];}int end=h/2+supply;for(int i=h/2+1; i<=end; i++)//填充码字 {d[i]=900;}for(int i=0; i<=end; i++){printf("%d\n", d[i]);}//暴力模拟执行到这一步,当s=-1时,都成立,能拿40分了//下面开始求校验码字,模拟多项式的求解以及多项式的除法int k=0;if(s!=-1)k=pow(2, s+1);//校验码字的个数int g[601]={0};//存储g(x)的系数(s最大是8,所以k最大是512,开601个就够了)g[0]=1;int a=-3;for(int i=1; i<=k; i++)//求g(x),模拟多项式的求解,多项式逐个括号相乘{for(int j=i; j>0; j--)//从后面开始求解,每次都把前面的系数进行迭代更新{g[j]=(g[j]+(g[j-1]*a))%929;//建议在草稿纸上模拟}a=(a*3)%929;}for(int i=0; i<n; i++)//取模运算 {for(int j=i+1; j<=i+k; j++)//每一次都消掉一个,然后更新后面k个{d[j]=d[j]-(d[i]*g[j-i])%929;//建议在草稿纸上模拟}}for(int i=n; i<n+k; i++){printf("%d\n", ((-d[i])%929+929)%929);//因为得到的是-r,所以输出要取反}return 0;
}

相信大家对前面40分的模拟都能理解明白,代码中也做了相应的注释,这里就不做赘述了。如果得分少于40的同学,建议先把前面40分模拟正确,检查一下循环判断的边界等等。

下面来讲一下多项式的求解以及多项式的除法:

多项式求解示意图:

每一次迭代都把前面的系数做一次更新,注意上一次迭代的结果各个系数对应的位置,以及本次迭代系数所在位置的变化,常数项永远在最后一位,所以对应的一次项倒数第二位置,但迭代过程中系数的位数不断加一,相当于各个项数也推迟了一位。(建议自己模拟一遍)

多项式的除法示意图:

多项式的除法就是这么一个意思, 我就没有把全部过程算完,大家理解意思即可。然后所得余数就是-r。那问题来了,为什么余数是-r?

等式两边同时除以g(x),即可得​​​​​​​​​​​​​​

所以,在输出的时候,要在系数前面加个负号。

以上就是全部的解答了,如果还有哪些不清楚的可以评论留言。希望能帮助到大家!

CSP—— 登机牌条码(多项式的求解以及多项式的除法)相关推荐

  1. CSP登机牌条码202112-3

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

  2. CSP CCF: 202112-3 登机牌条码 (C++)

    题目来源: 计算机软件能力认证考试系统 问题描述 试题编号: 202112-3 试题名称: 登机牌条码 时间限制: 1.0s 内存限制: 512.0MB 问题描述: 题目背景 西西艾弗岛景色优美,游人 ...

  3. matlab多项式加法运算,matlab多项式运算与代数方程求解解析.ppt

    * 多项式运算与代数方程求解 数学软件 Matlab Matlab基础及应用 * 多项式转化为符号表达式:poly2sym 四则运算:conv.deconv 导数与积分:ployder.polyint ...

  4. matlab根据根求多项式,matlab求解多项式的根

    因此牛顿法也称切线法,是非线性方程求根方法中收敛最快的方 法. 2. matlab 中方程求解的基本命令 roots(p):求多项式方程的根,其中 p 是多项式系数按降幂排列所形成的向量. solve ...

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

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

  6. 递归思想求解稀疏多项式的值

    利用递归思想求解指数连续增长的多项式的值用的是的秦九昭算法,从最里面的一层乘到最外面的一层,这个算法的效率要比一个项一个项的算的算法高出10倍. 这里的思想同秦九昭算法基本一致,唯一的差别就是稀疏多项 ...

  7. 第十九篇,解析法求解五阶多项式

    // x0为初始约束,时间为0:x1为结束约束,时间为t // coef_为求解结果,定义x=at^5 + bt^4 + ct^3 + dt^2 + et + f, // 则coef_[0]为f,co ...

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

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

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

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

  10. CSP202112-3登机牌条码

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

最新文章

  1. 【C 语言】结构体相关 的 函数 指针 数组
  2. Linux打开浏览器进程,Linux终端Web浏览器w3m
  3. mysql中使用CONCAT 实现拼接
  4. 错误An entity with the same identity already exists in this EntitySet RIA
  5. 关于竖表转横表的问题
  6. stream+springmvc实现文件断点续传
  7. jquery easy ui 1.3.4 事件与方法的使用(3)
  8. Linux启动脚本rc.local 不执行的解决方法
  9. 转:Java中的异常处理
  10. OAuth 2.0 in Web API #Reprinted
  11. PowerDesigner模型设计1
  12. ASP.NET 2.0运行原理及其过程简要分析
  13. devcon 用法2
  14. 在windows 2008下面使用dynamipsgui
  15. vue-cropper 截图
  16. scrapy项目:爬取豆瓣畅销书排行榜内容(仅爬取2020年1-3页:无保存)
  17. 时间与相关类型(2) - TDate、TTime、TTimeStamp
  18. 视频 | 皖南川藏线自驾游
  19. UVA 11134 Fabled Rook 枚举 multiset加速
  20. 自己用JavaScript写出吉他和弦图生成器

热门文章

  1. 2020幻影围棋 第三天围棋规则模块(一)
  2. 建立内网Windows补丁服务器
  3. python版js压缩工具
  4. 光流的基本概念和原理-Lucas–Kanade光流算法
  5. Android中Home键的监听和拦截
  6. 香槟分校计算机专业毕业生去向,2019年伊利诺伊州立大学香槟分校计算机专业排名_托普仕留学...
  7. Windows上WinRAR.exe命令行参数说明
  8. 大学生应该懂得。。。葡萄酒知识
  9. DruidDataSource详解部分(一)
  10. JavaWeb学习笔记(十三)之session的钝化和活化