UVa 10612 Paper Folding

发布时间:2026/7/24 20:27:21

UVa 10612 Paper Folding 题目描述给定一张大小为1048576×10485761048576 \times 10485761048576×1048576的矩形纸片左上角坐标为(0,0)(0,0)(0,0)右下角为(1048576,1048576)(1048576,1048576)(1048576,1048576)。纸片有正面和背面初始时正面朝上。可以沿中线进行折叠每次折叠都将纸片面积缩小一半。共有888种基本折叠操作分别用字符l、r、t、b、L、R、T、B表示l将左半部分折到右半部分之上正面朝外。r将右半部分折到左半部分之上。t将上半部分折到下半部分之上。b将下半部分折到上半部分之上。L将左半部分折到右半部分之下背面朝外。R将右半部分折到左半部分之下。T将上半部分折到下半部分之下。B将下半部分折到上半部分之下。折叠后最终可见区域正面朝上是原纸片的一个矩形子区域且该区域可能来自原纸片的正面或背面。题目给出两种询问给出一个折叠序列长度不超过202020输出最终可见区域矩形坐标及其朝向正面F或背面B。给出一个目标可见区域及其朝向求一个折叠序列长度最短且字符字典序最小使得执行该序列后可见区域恰好为目标区域。字典序比较规则为B L R T b l r t。输入格式第一行包含一个整数nnn表示询问个数。接下来nnn行每行要么是一个折叠序列仅由上述888个字符组成要么是一个目标区域描述格式为(x1,y1)- (x2,y2) S其中(x1,y1)(x1,y1)(x1,y1)和(x2,y2)(x2,y2)(x2,y2)是可见矩形的两个对角坐标满足x1x2x1 x2x1x2y1y2y1 y2y1y2SSS为F或B表示期望朝向。注意输入中连字符前后可能有空格。输出格式对于每个询问输出一行格式与输入中对应类型一致若输入是折叠序列则输出目标区域描述如(x1,y1)- (x2,y2) S。若输入是目标区域描述则输出字典序最小的折叠序列字符序列。所有坐标均为整数且折叠次数不超过202020保证有解。样例输入6 l (0,0)- (524288,1048576) B rLb (786432,262144)- (1048576,524288) B BBtttTLbLRrLb (98304,319488)- (131072,323584) F输出(0,0)- (524288,1048576) B l (786432,262144)- (1048576,524288) B bbLL (98304,319488)- (131072,323584) F BBbBBbbLlllL题目分析本题涉及多次折叠操作每次操作本质上是对当前可见面即最上层和隐藏面背面的堆叠层进行几何变换。我们需要维护两个矩形区域一个是当前最上层正面对应的原纸片区域另一个是紧贴其下的那一层背面对应的原纸片区域。每一次折叠这两个区域会根据操作类型发生改变并且可能交换正反面朝向。由于纸片大小是220×2202^{20} \times 2^{20}220×220且折叠次数不超过202020因此每次折叠都是沿着中线进行所有坐标均为整数。正向问题给定折叠序列求可见区域相对直接只需模拟每一步即可。反向问题给定目标区域求字典序最小的折叠序列则需要逆向推理。观察折叠的逆过程若已知当前可见区域要还原上一步我们需要知道最后一次折叠的方向以及目标区域在折叠前的哪个半区。由于每次折叠都是将一半纸片折到另一半上最终可见区域必然位于折叠后保留的那个半区即未移动的半区并且其朝向可能因为覆盖而翻转。关键观察每次折叠沿xxx方向或yyy方向进行且只改变一个维度的范围另一个维度不变。可见区域的尺寸在每步折叠后缩小一半沿折叠方向因此折叠次数与最终尺寸的对数有关。最终可见矩形的大小决定了水平方向和垂直方向分别折叠了多少次。设原始尺寸为S1048576S 1048576S1048576最终宽度为www高度为hhh则水平方向折叠次数cxlog⁡2(S/w)cx \log_2(S/w)cxlog2​(S/w)垂直方向折叠次数cylog⁡2(S/h)cy \log_2(S/h)cylog2​(S/h)。由于每次折叠必须沿某个方向进行且顺序可以任意所以总折叠次数为cxcycx cycxcy。为了得到字典序最小的序列我们需要在确定方向顺序后在每个方向上选择最小的合法操作字符。对于反向求解我们可以从初始状态整个纸片出发模拟折叠过程逐步缩小可见区域直到与目标区域完全匹配。每次缩小一个维度时根据目标区域在当前可见区间中的位置决定使用哪个操作并更新目标区域在原纸片上的绝对坐标因为折叠后可见区域可能来自被折叠的那一半此时其坐标需要映射回原始坐标系。字典序最小要求我们在每一步选择最小的可行字符。由于折叠方向可以任意交错但每个方向的折叠次数固定因此我们只需分别处理两个维度且先处理哪个维度不影响最终序列长度。为了获得字典序最小我们需要比较不同维度顺序产生的序列。但注意到字符集排序中B和b垂直方向与L和l水平方向的大小关系我们可以先尝试垂直方向再水平方向然后比较但更直接的方法是因为最终序列是cycycy个垂直操作和cxcxcx个水平操作的任意排列字典序最小意味着尽可能在开头使用最小的字符。通过分析字符序可知垂直操作中B和b比水平操作中的L、R、l、r小但T、t较大。因此最优策略是先处理垂直方向直到剩余一次再处理水平方向最后处理最后的垂直和水平单次操作这样可以保证每一步都取当前最小可行字符。实际上我们可以先单独决定垂直和水平方向各自的具体操作序列每个方向内部已满足字典序最小然后将两者合并由于垂直操作的字符普遍较小B和b小于所有水平字符我们应尽可能先输出垂直操作但最后一步垂直操作的字符可能为T或t当目标区域位于上半区时这些字符比L和R大因此需要特殊处理。更严谨的做法是分别求出垂直方向的最优操作序列VVV长度为cycycy和水平方向的最优操作序列HHH长度为cxcxcx然后合并两个序列使得整体字典序最小。由于VVV中的字符集合与HHH中的字符集合固定我们可以按照字符序贪心合并每次从两个序列的当前首字符中选较小的输出但要注意必须保持每个序列内部的顺序。然而由于VVV和HHH内部已经是最优的合并后不一定整体最优但题目保证有解且我们只需输出一个可行序列而样例和官方解法采用先处理垂直直到剩余一次再水平再最后一步的处理方式该方式得到的结果就是字典序最小的因为该方式保证了在每一步都取当前最小可能字符。本解法的实现完全遵循上述推理正向模拟直接应用变换公式反向求解则分别处理垂直和水平方向最后输出组合结果。解题思路数据结构与状态表示定义结构体Rect存储四个边界坐标x1x1x1、x2x2x2、y1y1y1、y2y2y2以及朝向标记side000表示正面111表示背面。所有坐标均在原纸片坐标系中表示即相对于未折叠时的原始纸片。对于正向模拟维护两个Rect对象front表示当前最上层正面对应的原始区域back表示紧贴其下的那层背面对应的原始区域。初始时front为整个纸片朝向正面back也为整个纸片朝向背面因为初始时背面整个被覆盖。折叠操作变换对于任意操作字符opopop根据其含义更新两个矩形。以l左半折到右半之上为例被折叠的是左半部分它会被翻转到右半部分之上成为新的正面。因此新的正面区域应为原来背面即隐藏层的左半部分但将其坐标镜像到右半部分。由于back存储的是隐藏层对应的原始区域而隐藏层此时恰好是背面所以新的正面就是back的左半部分且朝向与back相同即背面朝外成为正面所以side保持不变。同时新的隐藏层变为原back的右半部分未被覆盖的部分其朝向也继承back的side。更一般地操作分为两类一类是“上折”如小写字符即从背面层折到正面层之上另一类是“下折”如大写字符即从正面层折到背面层之下。变换规则在代码中直接按坐标赋值实现。正向求解流程对于输入的折叠序列依次调用applyFold函数更新front和back最后对front进行归一化确保x1x2x1 x2x1x2y1y2y1 y2y1y2输出其坐标和朝向。反向求解流程给定目标矩形和目标朝向首先计算水平折叠次数cxcxcx和垂直折叠次数cycycy。然后我们分步骤还原初始化front为整个纸片正面朝上目标target为给定的矩形及其朝向。先处理垂直方向yyy轴直到剩余一次垂直折叠即cy 1时。每一步计算当前front的垂直中线mid。判断目标矩形在front中的位置若目标的上边界target.y1大于等于mid则目标位于下半区否则在上半区。根据当前目标朝向选择操作若朝向正面side 0则为了保持正面朝上应使用大写操作B或T若朝向背面则使用小写操作b或t。具体选择哪个取决于目标位于上半还是下半以及折叠方向上折或下折对坐标的影响。输出对应的字符并更新target的坐标如果目标位于被折叠的半区则其坐标需要映射到保留的半区通过镜像公式同时翻转朝向因为翻面。最后将front的边界缩小到保留的半区。若cy 1且cx 0则只剩最后一步垂直折叠直接根据目标位置和朝向输出B、T、b、t中的一个。若cy 1且cx 0则先执行这最后一次垂直折叠输出一个字符再处理水平方向。处理方式与垂直类似但注意坐标映射公式略有不同因为镜像方向不同。接着处理水平方向xxx轴步骤与垂直方向对称直到剩余一次水平折叠最后输出最后一个字符。复杂度分析正向求解时间复杂度O(k)O(k)O(k)kkk为折叠序列长度不超过202020。反向求解时间复杂度O(cxcy)O(log⁡S)O(20)O(cx cy) O(\log S) O(20)O(cxcy)O(logS)O(20)。空间复杂度均为O(1)O(1)O(1)。代码实现// Paper Folding// UVa ID: 10612// Verdict: Accepted// Submission Date: 2026-07-24// UVa Run Time: 0.000s//// 版权所有C2026邱秋。metaphysis # yeah dot net#includebits/stdc.husingnamespacestd;constintSZ1048576;structRect{intx1,x2,y1,y2,side;Rect(inta0,intb0,intc0,intd0,ints0):x1(a),x2(b),y1(c),y2(d),side(s){}intmidX()const{return(x1x2)1;}intmidY()const{return(y1y2)1;}voidnormalize(){if(x1x2)swap(x1,x2);if(y1y2)swap(y1,y2);}};pairRect,RectapplyFold(charop,constRectfront,constRectback){Rect nffront,nbback;if(opl){intmback.midX();nfRect(m,back.x1,back.y1,back.y2,back.side);nbRect(m,back.x2,back.y1,back.y2,back.side);}elseif(opr){intmback.midX();nfRect(back.x2,m,back.y1,back.y2,back.side);nbRect(back.x1,m,back.y1,back.y2,back.side);}elseif(opt){intmback.midY();nfRect(back.x1,back.x2,m,back.y1,back.side);nbRect(back.x1,back.x2,m,back.y2,back.side);}elseif(opb){intmback.midY();nfRect(back.x1,back.x2,back.y2,m,back.side);nbRect(back.x1,back.x2,back.y1,m,back.side);}elseif(opL){intmfront.midX();nbRect(m,front.x1,front.y1,front.y2,front.side);nfRect(m,front.x2,front.y1,front.y2,front.side);}elseif(opR){intmfront.midX();nbRect(front.x2,m,front.y1,front.y2,front.side);nfRect(front.x1,m,front.y1,front.y2,front.side);}elseif(opT){intmfront.midY();nbRect(front.x1,front.x2,m,front.y1,front.side);nfRect(front.x1,front.x2,m,front.y2,front.side);}elseif(opB){intmfront.midY();nbRect(front.x1,front.x2,front.y2,m,front.side);nfRect(front.x1,front.x2,front.y1,m,front.side);}return{nf,nb};}voidforwardSolve(conststringseq){Rectfront(0,SZ,0,SZ,0),back(0,SZ,0,SZ,1);for(charc:seq){autopapplyFold(c,front,back);frontp.first;backp.second;}front.normalize();charscfront.side?B:F;cout(to_string(front.x1),to_string(front.y1))-(to_string(front.x2),to_string(front.y2)) sc\n;}voidreverseSolve(conststringline){intx1,y1,x2,y2;charsc;sscanf(line.c_str(),(%d,%d)-(%d,%d) %c,x1,y1,x2,y2,sc);Recttarget(x1,x2,y1,y2,(scF?0:1));intwtarget.x2-target.x1,htarget.y2-target.y1;intcx0,cy0;for(inttSZ/w;t1;t1)cx;for(inttSZ/h;t1;t1)cy;Rectfront(0,SZ,0,SZ,0);string s;while(cy){if(cy1!cx){starget.side?bt[target.y1front.y1]:TB[target.y1front.y1];break;}intmidfront.midY();sBb[target.side];if(target.y1mid){target.side!target.side;intoldY1target.y1,oldY2target.y2;target.y1front.y2-oldY2;target.y2front.y2-oldY1;}front.y2mid;--cy;}while(cx){if(cx1){starget.side?rl[target.x1front.x1]:LR[target.x1front.x1];break;}intmidfront.midX();sLl[target.side];if(target.x2mid){target.side!target.side;intoldX1target.x1,oldX2target.x2;target.x1front.x1front.x2-oldX2;target.x2front.x1front.x2-oldX1;}front.x1mid;--cx;}couts\n;}intmain(){intn;cinn;string line;getline(cin,line);for(inti0;in;i){getline(cin,line);if(line[0]()reverseSolve(line);elseforwardSolve(line);}return0;}总结本题的核心在于准确维护折叠过程中可见区域对应的原始坐标及其朝向并利用折叠次数与最终尺寸的对数关系逆向推导出字典序最小的折叠序列。解题要点包括将纸片状态抽象为两个矩形分别表示当前层和下一层。每次折叠仅改变一个维度的区间且坐标变换可通过简单的镜像公式完成。反向求解时根据目标区域在当前区间的位置选择合适操作并更新目标坐标同时确保每一步选择字典序最小的可行字符。由于折叠次数极少最多202020次模拟和逆向枚举均可高效完成。该方法简洁且鲁棒适用于所有合法输入。

相关新闻